What is the difference among the functions doall dorun doseq and for?

Clojure

Clojure Problem Overview


What is the difference between the functions doall, dorun, doseq, and for ?

I found some information scattered throughout the internet, but I think it would be better to centralize that information here.

Clojure Solutions


Solution 1 - Clojure

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 seq
  • doseq - 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.

Solution 2 - Clojure

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCarlos NunesView Question on Stackoverflow
Solution 1 - ClojureoverthinkView Answer on Stackoverflow
Solution 2 - ClojureThumbnailView Answer on Stackoverflow