2012-07-23 12 views
6

Perché questo pezzo di codice Clojure:Clojure costantemente e la funzione mappa

user=> (map (constantly (println "Loop it.")) (range 0 3)) 

Resa questa uscita:

Loop it. 
(nil nil nil) 

mi aspetto che per stampare "loop" tre volte come un lato effetto di valutare la funzione tre volte.

risposta

9

constantly non valuta il suo argomento più volte. È una funzione, non una macro, quindi l'argomento viene valutato esattamente una volta prima delle esecuzioni constantly. Tutto il constantly esegue il suo argomento (valutato) e restituisce una funzione che restituisce il valore dato ogni volta che viene chiamato (senza rivalutare nulla poiché, come ho detto, l'argomento viene valutato già prima delle esecuzioni uguali constantly).

Se tutto ciò che si vuole fare è chiamare (println "Loop it") per ogni elemento dell'intervallo, è necessario farlo passare come funzione per mappare invece di constantly. Nota che dovrai effettivamente passarlo come una funzione, non come un'espressione valutata.

+0

Guardato alla fonte. Questo sembra un vincitore. – Mike

+0

Stavo cercando di usare costantemente per evitare di passare esplicitamente un argomento di cui non ho bisogno. Si accontenterà di questo, però. – Mike

+10

Nota che se vuoi solo effetti collaterali, dovresti usare 'doseq' o' dotimes'. Dato che 'map' è pigro, non otterrai il risultato desiderato a meno che non lo imponi con' doall' o 'dorun'. –

3

È possibile ottenere un comportamento vicino al proprio intento utilizzando repeatedly e un'espressione lambda.

Per esempio:

(repeatedly 3 #(println "Loop it")) 

meno che non sei al REPL, questo ha bisogno di essere circondato da un dorun o simili. repeatedly è pigro.

+0

Lambda non si compilerà a causa del fatto che desidera utilizzare l'argomento che gli passo. In questo caso, preferirei semplicemente ignorare l'argomento. – Mike

+0

Ho aggiunto un esempio di utilizzo, analogo al tuo. – sortega

+0

Oh, questo ha molto più senso. Grazie! – Mike

3

Come correttamente sottolineato da sepp2k constantly è una funzione, quindi il suo argomento verrà valutato solo una volta.

Il modo idiomatico per ottenere quello che state facendo qui sarebbe quella di utilizzare doseq:

(doseq [i (range 0 3)] 
    (println "Loop it.")) 

Oppure, in alternativa dotimes (che è un po 'più conciso ed efficace in questo caso particolare, come non sono in realtà utilizza la sequenza prodotta da range):

(dotimes [i 3] 
    (println "Loop it.")) 

Entrambe queste soluzioni non sono pigri, che è probabilmente quello che vuoi se si sta solo eseguendo del codice per gli effetti collaterali.

Problemi correlati