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 forcostruisce 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 defmodulo restituisce la nuova var creata e non il valore ad essa associato, non c'è nulla da stampare per REPL e lazyfarà riferimento a un lazy-seq non realizzato: nessuno dei suoi elementi è stato calcolato affatto. eagerfarà riferimento a nil, e tutta la stampa sarà stata eseguita.