4

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)
John Wang
  • 4,562
  • 9
  • 37
  • 54

2 Answers2

3

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.

amalloy
  • 89,153
  • 8
  • 140
  • 205
2

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)
Omri Bernstein
  • 1,893
  • 1
  • 13
  • 17