I was browsing the source of clojure.core:
(defmacro and
([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
Why not just
(defmacro and
([] true)
([x] x)
([x & next]
`(if ~x (and ~@next) ~x)))
Because the argument x
is a form, which might be any expression, that can be evaluated twice in (if ~x (and ~@next) ~x))
. The let
evaluates it once and uses the value x#
thereafter.
So the actual code avoids the effects - the side effects in particular - of evaluating the arguments twice.
@amalloy points out that the second instance of form x
in (if ~x (and ~@next) ~x))
is evaluated only if the first instance evaluates false(y).