I couldn't understand the difference between macroexpand and macroexpand-1.
Could you provide examples?
I couldn't understand the difference between macroexpand and macroexpand-1.
Could you provide examples?
Let's say we have the following code:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
Then, doc of macroexpand-1
says:
If form represents a macro form, returns its expansion, else returns form.
Indeed, it does:
user> (macroexpand-1 '(inner-macro "hello"))
(clojure.core/println "hello")
user> (macroexpand-1 '(top-level-macro "hello"))
(user/inner-macro "hello")
user> (macroexpand-1 '(not-a-macro))
(not-a-macro)
In other words, macroexpand-1
does just one step of macroexpansion if supplied form is a macro form.
Then, doc of macroexpand
:
Repeatedly calls macroexpand-1 on form until it no longer represents a macro form, then returns it.
Example:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
What happened? As soon as, (top-level-macro "hello")
expands to (user/inner-macro "hello")
, which is macro form, macroexpand
will perform expansion once again. The result of second expansion is (clojure.core/println "hello")
. It is not a macro form, so macroexpand
just returns it.
So, just to rephrase the doc, macroexpand
will recursively do expansion until top level form is not a macro form.
Also there's additional note in macroexpand
's doc:
Note neither macroexpand-1 nor macroexpand expand macros in subforms.
What does that mean? Let's say we have one more macro:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
Let's try to expand it:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
Since, (do ...)
form is not a macro macroexpand-1
and macroexpand
just return it and nothing more. Don't expect that macroexpand
will do the following:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
the difference is quite simple. First of all the background: when the compiler sees macro call it tries to expand it according to its definition. If the code, generated by this macro contains other macros, they are also expanded by compiler, and so on, until resulting code is totally macros-free. So macroexpand-1
just expands the topmost macro and shows the result (no matter does it generate another macro calls), while macroexpand
tries to follow the compiler's pipeline (partially, not expanding macros in subforms. To make the complete expansion you should take a look at clojure.walk/maxroexpand-all
).
small example:
user> (defmacro dummy [& body]
`(-> ~@body))
#'user/dummy
this silly macro generates the call to another macro ( ->
)
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
just expands dummy
, but keeps ->
unexpanded
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
expands dummy
and then expands ->