2011-12-16 13 views
11

Sono nuovo di Clojure e ho scoperto che quando eseguo il loop su questo vettore in clojure utilizzando una list comprehension ottengo alcuni nil alla fine.Looping di vettori

(def myVec [1,2,3]) 

user=> (for [x myVec] (println x)) 
(1 
2 
3 
nil nil nil) 

ottengo la stessa cosa usando map

user=> (map println myVec) 
(1 
2 
3 
nil nil nil) 

ciò che provoca il nill da stampare in questi casi?

+2

utilizzando (doseq [x myVec] (println x)) – BLUEPIXY

risposta

6

Quelle nil sono il valore restituito di println. Ogni volta che si chiama

(println "something") 

le stampe funzione printlnsomething sullo standard output, e poi ritorna nil. L'effetto complessivo nel codice è che si visualizzano tutti gli effetti collaterali (I/O) di tutte le chiamate println, quindi REPL stampa il valore restituito proveniente da ciascuna chiamata (ad esempio tre volte nil).

9

for e map creare una nuova sequenza artificiale con ogni elemento del vettore originale sostituito dal risultato di (println element), e println ritorna NIL.

Non utilizzare for e map per eseguire effetti indesiderati (come la stampa) sugli elementi. Utilizzare doseq per quello.

+0

Un po 'di confusione deriva dall'ordine in cui i dati vengono stampati. La parentesi iniziale viene stampata come parte dell'elenco che (map (println ...)) restituisce, quindi si ottiene l'output di ogni println, quindi i nils che fanno parte dell'elenco di (map (println ...)) . Se si passa ad usare doseq, o se si (doall (map (println ...))), i risultati saranno un po 'meno ambigui visto che vedrete tutte le stampe prima di ottenere i valori di ritorno. (dorun (map (println ...))) restituirà solo. A meno che non ottenga Dorun e Doall invertiti. –

+4

@ SavanniD'Gerinel Le cose che stai dicendo sono vagamente vere, ma sbagliate nella maggior parte dei particolari. Le cose vengono fuori nell'ordine "sbagliato" perché la sequenza è chunked, non perché il repl stampa gli effetti secondari prima dei valori: se tu avessi una sequenza non sincronizzata come '(prendi 10 (iterate # (inc (doto% println)) 0)) ', vedresti i valori di ritorno interlacciati con i risultati di stampa. Allo stesso modo, se avessi una lista più grande di una singola porzione (ad esempio della dimensione 50), otterresti un mucchio di stampe, quindi un mucchio di valori, quindi più stampe ... – amalloy

+0

Questo è informativo. L'essenza di quello che stavo dicendo era che non si poteva realmente prevedere l'ordine in cui venivano stampate le cose, ma anche questo sarebbe stato impreciso dato lo smembramento a cui ci si riferisce qui. Così com'è, sono diventato consapevole solo di alcuni giorni fa. –

1

nil è il valore restituito da println in modo da visualizzare le linee stampate seguite dall'elenco mappato di valori nulli.