Qual è la differenza tra doseq e for in Clojure? Quali sono alcuni esempi di quando sceglieresti di usarne uno sull'altro?
Qual è la differenza tra doseq e for in Clojure? Quali sono alcuni esempi di quando sceglieresti di usarne uno sull'altro?
Risposte:
La differenza è che for
costruisce una sequenza pigra e la restituisce mentre doseq
è per l'esecuzione di effetti collaterali e restituisce zero.
user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil
Se vuoi costruire una nuova sequenza basata su altre sequenze, usa per. Se vuoi creare effetti collaterali (stampa, scrittura su un database, lancio di una testata nucleare, ecc.) Basati su elementi di alcune sequenze, usa doseq.
Nota anche che doseq
è desideroso mentre for
è pigro. L'esempio che manca nella risposta di Rayne è
(for [x [1 2 3]] (println x))
Al REPL, questo generalmente farà quello che vuoi, ma è fondamentalmente una coincidenza: il REPL forza la sequenza pigra prodotta da for
, provocando la stampa. In un ambiente non interattivo, non verrà mai stampato nulla. Puoi vederlo in azione confrontando i risultati di
user> (def lazy (for [x [1 2 3]] (println 'lazy x)))
#'user/lazy
user> (def eager (doseq [x [1 2 3]] (println 'eager x)))
eager 1
eager 2
eager 3
#'user/eager
Poiché il def
modulo restituisce la nuova var creata e non il valore ad essa associato, non c'è nulla da stampare per REPL e lazy
farà riferimento a un lazy-seq non realizzato: nessuno dei suoi elementi è stato calcolato affatto. eager
farà riferimento a nil
, e tutta la stampa sarà stata eseguita.