我无法理解macroexpand和macroexpand-1之间的区别。
你能提供一些例子吗?
答案 0 :(得分:11)
假设我们有以下代码:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
然后,macroexpand-1
的文件说:
如果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
的文件:
在窗体上反复调用macroexpand-1,直到它不再存在 代表一个宏形式,然后返回它。
示例:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
发生什么事了?只要(top-level-macro "hello")
扩展为(user/inner-macro "hello")
,这是宏格式,macroexpand
将再次执行扩展。第二次扩展的结果是(clojure.core/println "hello")
。它不是宏形式,因此macroexpand
只返回它。
因此,只需重新定义文档,macroexpand
将递归执行扩展,直到 顶级 表单不是宏格式。
macroexpand
的文档中还有其他说明:
请注意,macroexpand-1和macroexpand都不会在子表单中展开宏。
这是什么意思?假设我们还有一个宏:
(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
只是返回它而已。不要指望macroexpand
会执行以下操作:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
答案 1 :(得分:4)
差异很简单。首先是背景:当编译器看到宏调用时,它会尝试根据其定义扩展它。如果由此宏生成的代码包含其他宏,则它们也会被编译器扩展,依此类推,直到生成的代码完全无宏。所以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
,然后展开->