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?
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
.