Search code examples
clojureleiningenread-eval-print-loop

Clojure and Leiningen: Why is `doall` needed in this example?


I'm currently using Leiningen to learn Clojure and I'm confused about the requirement of doall for running this function:

;; take a function (for my purposes, println for output formatting) and repeat it n times
(defn repeat [f n] (for [i (range n)] (f)))

(repeat println 2) works just fine in an REPL session, but not when running with lein run unless I include the doall wrapper. (doall (repeat println 2)) works and I'm curious why. Without it, lein run doesn't show the two blank lines in the output.

I also have:

(defmacro newPrint1 [& args] `'(println ~args))
(defmacro newPrint2 [& args] `'(println ~@args))

The first function I thought of myself. The next two macros are examples from a tutorial video I'm following on Udemy. Even if I wrap the macro calls with doall, such as (doall (newPrint1 1 2 3)), lein run produces no output, but (newPrint1 1 2 3) in a terminal REPL session produces the desired output of (clojure.core/println (1 2 3)) as it does in the video tutorial. Why doesn't doall work here?


Solution

  • for creates a lazy sequence. This lazy sequence is returned. The P in REPL (read eval Print loop) prints the sequence, thus realizing it. For realizing, the code to produce each element is run.

    If you do not use the sequence, it is not realized, so the code is never run. In non-interactive use, this is likely the case. As noted, doall forces realization.

    If you want to do side-effects, doseq is often better suited than for.