In the book Programming Clojure(Stuart), when read how macros are expanded I got confused.
user=> (defmacro chain
([x form] (list '. x form))
([x form & more] (concat (list 'chain (list '. x form)) more)))
#'user/chain
The above macro can be expanded as:
user=> (macroexpand '(chain a b c))
(. (. a b) c)
But the following is only expanded to the first level:
user=> (macroexpand '(and a b c))
(let* [and__3822__auto__ a]
(if and__3822__auto__ (clojure.core/and b c) and__3822__auto__))
The and macro source:
user=> (source and)
(defmacro and([] true)
([x] x)
([x & next]
`(let [and# ~x]
(if and# (and ~@next) and#))))
Why is the chain macro expanded all the way but the and not ? Why is it not expanded to something like the following:
user=> (macroexpand '(chain a b c d))
(. (chain a b c) d)
macroexpand
expands the outermost form over and over until it gets a non-macro result. If you want to see just the output of a single phase of macroexpansion, use macroexpand-1
.
So the difference is, chain
's recursive call is first, and and
's is not.
To me, amalloy's response directly answers your question. However, if veiled beneath your question, you are wondering how to show the fully macroexpanded form of something, I would point you in the direction of clojure.walk's macroexpand-all
. Using your same example, now with macroexpand-all:
user=> (macroexpand-all '(and a b c))
(let* [and__3546__auto__ a]
(if and__3546__auto__
(let* [and__3546__auto__ b]
(if and__3546__auto__ c and__3546__auto__))
and__3546__auto__))
All macros have been expanded. Also notice that for your first example, it will behave the same as macroexpand
(for the reasons amalloy gave):
user=> (macroexpand-all '(chain a b c))
(. (. a b) c)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With