What is the difference between the functions doall
, dorun
, doseq
, and for
?
I found some information scattered throug
dorun
, doall
, and doseq
are all for forcing lazy sequences, presumably to get side effects.
dorun
- don't hold whole seq in memory while forcing, return nil
doall
- hold whole seq in memory while forcing (i.e. all of it) and return the seqdoseq
- same as dorun
, but gives you chance to do something with each element as it's forced; returns nil
for
is different in that it's a list comprehension, and isn't related to forcing effects. doseq
and for
have the same binding syntax, which may be a source of confusion, but doseq
always returns nil
, and for
returns a lazy seq.
You can see how dorun
and doall
relate to one another by looking at the (simplified) source code:
(defn dorun [coll]
(when (seq coll) (recur (next coll))))
(defn doall [coll] (dorun coll) coll)
dorun
runs through the sequence, forgetting it as it goes,
ultimately returning nil
.doall
returns its sequence argument, now realised by the dorun
.Similarly, we could implement doseq
in terms of dorun
and for
:
(defmacro doseq [seq-exprs & body]
`(dorun (for ~seq-exprs ~@body)))
For some reason, performance perhaps, this is not done. The standard doseq
is written out in full, imitating for
.