When to use doall and dorun in Clojure

The lazy sequence in Clojure is a confusing part for many beginners, especially when it used together with side effects. The catch is, depends on the actual way by which the lazy sequence is consumed, the items in the sequence can be fully, partially or completely not consumed. If there is no side effect operation in the items, nothing unusual will be observed. If the items are supposed to cause side effects and the sequence is not fully consumed, unexpected behavior will occur.

The most common mistake is to use map to cause side effects but treat it like a for loop in imperative language. The example below demonstrate it.

 
(defn foo []
  (println "hello")
  (map #(println %) [1 2 3])
  "return"
)
 
(foo)
 

The number will not be printed, because the lazy sequence is not consumed by anyone, no item in the sequence is evaluated. In this case, we should surround the map with a dorun.

 
(defn foo []
  (println "hello")
  (dorun (map #(println %) [1 2 3]))
  "return"
)
 

The dorun simply de-lazy the lazy sequence, and nothing more. It also breaks the semantic of map which is supposed to transform a sequence and returns another sequence. The dorun returns nil instead of another sequence.

Another situation is you need to cause side effects and also return something, in another words, you want to fully evaluate the sequence and also keep the semantics of map. For example you can apply another map on the returned sequence. In this case you should use doall as shown below.

 
(println (take 2 (dorun (map #(do (println %) %) (range 33)))))
(println (take 2 (doall (map #(do (println %) %) (range 33)))))
(println (take 2 (map #(do (println %) %) (range 33))))
 

For the first line, all 33 numbers are printed, but take returns nil. The second is the same as first line except take returns (0 1). The third line is partially evaluated, only 32 numbers are printed out and take works as expected.