Unterschied zwischen doseq und for in Clojure

105

Was ist der Unterschied zwischen doseq und for in Clojure? Was sind einige Beispiele dafür, wann Sie eines über dem anderen verwenden würden?

Jeff der Bär
quelle

Antworten:

167

Der Unterschied besteht darin, dass foreine verzögerte Sequenz erstellt und zurückgegeben wird, während doseqNebenwirkungen ausgeführt werden, und Null zurückgegeben wird.

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

Wenn Sie eine neue Sequenz basierend auf anderen Sequenzen erstellen möchten, verwenden Sie für. Wenn Sie Nebenwirkungen (Drucken, Schreiben in eine Datenbank, Starten eines Atomsprengkopfs usw.) basierend auf Elementen aus einigen Sequenzen verursachen möchten, verwenden Sie doseq.

Rayne
quelle
11
Nun, das sind viele Nebenwirkungen ... Start eines Atomsprengkopfes :)
Marc
6
Vielen Dank! Ich hatte meine (längst verschwundenen) Haare mit "für" gezogen, damit meine Atomsprengköpfe niemals über meine Liste von Gegenständen geschossen wurden. "doseq" hat es sicher getan.
Yu Shen
Dies ist eine großartige Möglichkeit, die Unterscheidung zu treffen.
Jskulski
60

Beachten Sie auch, dass doseqeifrig ist, während forfaul ist. Das Beispiel, das in Raynes Antwort fehlt, ist

(for [x [1 2 3]] (println x))

Bei der REPL wird dies im Allgemeinen das tun, was Sie wollen, aber das ist im Grunde ein Zufall: Die REPL erzwingt die von erzeugte verzögerte Sequenz for, wodurch die Druckvorgänge ausgeführt werden. In einer nicht interaktiven Umgebung wird niemals etwas gedruckt. Sie können dies in Aktion sehen, indem Sie die Ergebnisse von vergleichen

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

Da das defFormular die neu erstellte Variable und nicht den daran gebundenen Wert zurückgibt, kann die REPL nichts drucken und lazyverweist auf eine nicht realisierte Lazy-Seq: Keines ihrer Elemente wurde überhaupt berechnet. eagerwird sich darauf beziehen nil, und der gesamte Druck wurde durchgeführt.

Amalloy
quelle
Wie geht doseq mit der Bewertung der unendlichen faulen Sequenz um? schlechte Idee? Nennen Sie es nur auf endlichen Sequenzen, entweder eifrig oder faul?
Johnbakers
@johnbakers Es wird für immer blockiert, bis die Auswertung unterbrochen wird. Clojure versucht niemals, unendliche Sequenzen anders zu behandeln als endliche Sequenzen.
Radon Rosborough