我不太明白macroexpand和macroexpand-1之间的区别。
你能举个例子吗?
我不太明白macroexpand和macroexpand-1之间的区别。
你能举个例子吗?
假设我们有以下代码:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
然后,macroexpand-1
的文档说:
如果表单表示一个宏形式,则返回其展开,否则返回表单本身。
确实如此:
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"))
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
,然后再扩展 ->