for macro accepts two arguments: a sequence of binding forms, and a body expression. As such, if I want to do multiple things in the loop, I have to wrap multiple expressions in a
do block to make them a single expression.
(doseq [a (range 3)]
(prn 'a a)
(for [a (range 3)]
(prn 'a a)
doseq works as expected. The
clojure.lang.ArityException: Wrong number of args (3) passed to: core/for
My question is, why doesn't this work? Why didn't the designer(s) of Clojure allow multiple "body" expressions in the for loop, like they did in
when? It's not as if there is any semantic ambiguity, right?
for is not a loop, it is lazy list comprehension. Since only the value of last expression in the body of a (implicit)
do is returned, any other expressions would have to exist merely for side effects. Execution for side-effects is the job of
doseq, which is why it has an implicit
for does not should be a reminder, do you really want side effects in your lazy sequence? Though there are legitimate reasons for doing so, care is warranted that those side effects execute when you want.
(def foo (for [a (range 32)] (do (prn (str "a is " a)) (inc a)))) (take 1 foo) ;=> ("a is 0" "a is 1" ... "a is 31" 1) ; <= the return value (take 10 foo) ;=> (1 2 3 4 5 6 7 8 9 10) ; aw, no side effects this time