What is the difference between macro exposure and macro exposure-1 in Clojure

I could not understand the difference between macroexpand and macroexpand-1.

Could you give some examples?

+6
source share
2 answers

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 macroexpand-1 says:

If the form is a macro, its extension is returned, else returns the form.

In fact, he 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 performs only one macro-expansion step if the provided form is a macroscopic form.

Then doc macroexpand :

Repeatedly calls macro instance-1 in the form until it is no longer a macro, and 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 a macro form, macroexpand will do the extension again. The result of the second decomposition is (clojure.core/println "hello") . This is not a macroform, so macroexpand just returns it.

So, just to paraphrase a document, macroexpand will recursively perform the expansion until the top-level form becomes a macro.

There is also a note in the macroexpand doc:

Please note: macro-1 and macro-distributed macros in macro files are not supported.

What does it mean? Let's say we have another macro:

 (defmacro subform-macro [arg] `(do (inner-macro ~arg))) 

Let's try to deploy it:

 user> (macroexpand-1 '(subform-macro "hello")) (do (user/inner-macro "hello")) user> (macroexpand '(subform-macro "hello")) (do (user/inner-macro "hello")) 

Since the form (do ...) not a macroexpand-1 macro and macroexpand , just return it and nothing else. Do not expect macroexpand to do the following:

 user> (macroexpand '(subform-macro "hello")) (do (clojure.core/println "hello")) 
+9
source

the difference is pretty simple. First of all, the background: when the compiler sees a 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 the compiler, etc., until the resulting code becomes completely without macros. Thus, macroexpand-1 simply extends the top macro and shows the result (regardless of whether it generates other macro calls), and macroexpand tries to follow the compiler pipeline (partially, without expanding macros in subformats. clojure.walk/maxroexpand-all look at clojure.walk/maxroexpand-all )

small example:

 user> (defmacro dummy [& body] `(-> ~@body )) #'user/dummy 

this stupid macro generates a call to another macro ( -> )

 user> (macroexpand-1 '(dummy 1 (+ 1))) (clojure.core/-> 1 (+ 1)) 

macroexpand-1 just extends dummy but retains -> unexpanded

 user> (macroexpand '(dummy 1 (+ 1))) (+ 1 1) 

macroexpand expands dummy and then expands ->

+4
source

All Articles