Clojure 中的 macroexpand 和 macroexpand-1 有什么区别
What is the difference between macroexpand and macroexpand-1 in Clojure
我无法理解 macroexpand 和 macroexpand-1 之间的区别。
能否提供示例?
假设我们有以下代码:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
然后,macroexpand-1
的医生说:
If form represents a macro form, returns its expansion,
else returns form.
的确如此:
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)
换句话说,如果提供的形式是宏形式,macroexpand-1
只做一步宏展开。
然后,macroexpand
的文档:
Repeatedly calls macroexpand-1 on form until it no longer
represents a macro form, then returns it.
示例:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
发生了什么事?一旦(top-level-macro "hello")
扩展为(user/inner-macro "hello")
,即宏形式,macroexpand
将再次进行扩展。二次展开的结果是(clojure.core/println "hello")
。它不是宏形式,所以 macroexpand
就 return 就可以了。
所以,只是为了改写文档,macroexpand
将递归地进行扩展,直到 top level 表单不是宏形式。
macroexpand
的文档中还有附加说明:
Note neither macroexpand-1 nor macroexpand expand macros in subforms.
这是什么意思?假设我们还有一个宏:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
让我们尝试扩展它:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
因为,(do ...)
形式不是宏 macroexpand-1
而 macroexpand
只是 return 它而已。不要期望 macroexpand
会执行以下操作:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
区别很简单。首先是背景:当编译器看到宏调用时,它会尝试根据其定义对其进行扩展。如果此宏生成的代码包含其他宏,它们也会被编译器扩展,依此类推,直到生成的代码完全不含宏。所以 macroexpand-1
只是扩展最顶层的宏并显示结果(不管它是否生成另一个宏调用),而 macroexpand
试图遵循编译器的管道(部分地,不扩展子窗体中的宏。使完整的扩展你应该看看 clojure.walk/maxroexpand-all
).
小例子:
user> (defmacro dummy [& body]
`(-> ~@body))
#'user/dummy
这个愚蠢的宏生成对另一个宏 (->
) 的调用
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
只是扩展 dummy
,但保持 ->
未扩展
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
扩展 dummy
然后扩展 ->
我无法理解 macroexpand 和 macroexpand-1 之间的区别。
能否提供示例?
假设我们有以下代码:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
然后,macroexpand-1
的医生说:
If form represents a macro form, returns its expansion, else returns form.
的确如此:
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)
换句话说,如果提供的形式是宏形式,macroexpand-1
只做一步宏展开。
然后,macroexpand
的文档:
Repeatedly calls macroexpand-1 on form until it no longer represents a macro form, then returns it.
示例:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
发生了什么事?一旦(top-level-macro "hello")
扩展为(user/inner-macro "hello")
,即宏形式,macroexpand
将再次进行扩展。二次展开的结果是(clojure.core/println "hello")
。它不是宏形式,所以 macroexpand
就 return 就可以了。
所以,只是为了改写文档,macroexpand
将递归地进行扩展,直到 top level 表单不是宏形式。
macroexpand
的文档中还有附加说明:
Note neither macroexpand-1 nor macroexpand expand macros in subforms.
这是什么意思?假设我们还有一个宏:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
让我们尝试扩展它:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
因为,(do ...)
形式不是宏 macroexpand-1
而 macroexpand
只是 return 它而已。不要期望 macroexpand
会执行以下操作:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
区别很简单。首先是背景:当编译器看到宏调用时,它会尝试根据其定义对其进行扩展。如果此宏生成的代码包含其他宏,它们也会被编译器扩展,依此类推,直到生成的代码完全不含宏。所以 macroexpand-1
只是扩展最顶层的宏并显示结果(不管它是否生成另一个宏调用),而 macroexpand
试图遵循编译器的管道(部分地,不扩展子窗体中的宏。使完整的扩展你应该看看 clojure.walk/maxroexpand-all
).
小例子:
user> (defmacro dummy [& body]
`(-> ~@body))
#'user/dummy
这个愚蠢的宏生成对另一个宏 (->
) 的调用
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
只是扩展 dummy
,但保持 ->
未扩展
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
扩展 dummy
然后扩展 ->