这是我可以做的最简单的例子:
(defmacro printer [& forms]
`(println ~@forms))
(defmacro adder [s]
`(inc ~s))
可以按预期使用它们:
(printer "haha")
=> "haha"
(adder 1)
=> 2
我可以macroexpand
他们看看宏做了什么:
(macroexpand '(printer 1))
=> (clojure.core/println 1)
(macroexpand '(adder 1))
=> (clojure.core/inc 1)
但是当它们嵌套时我得不到我想要的东西:
(macroexpand '(printer (adder 1)))
=> (clojure.core.println (adder 1))
我希望得到
=> (clojure.core.println (clojure.core/inc 1))
有没有办法扩展嵌套宏? 这对我调试特定错误有很大帮助。
答案 0 :(得分:5)
(use 'clojure.walk)
(macroexpand-all '(printer (adder 1)))
;(clojure.core/println (clojure.core/inc 1))
答案 1 :(得分:1)
感谢接受我的回答,我很高兴它有所帮助。我忘了补充一点,如果你想完全扩展编译器看到的内容,你可以利用clojure分析器的强大功能:
(use '[clojure.tools.analyzer.passes.jvm.emit-form :only [emit-form emit-hygienic-form]]
'[clojure.tools.analyzer.jvm :only [analyze]])
(emit-form (analyze '(printer (adder 1))))
(emit-hygienic-form (analyze '(printer (adder 1))))
上述两个结果与macroexpand-all
的结果几乎相同,但应涵盖macroexpand-all
可能无法完全发挥作用的极端情况。在您的示例中,它将inc
扩展为inc
定义内的内联函数。此外,如果要检查阴影,emit-hygienic-form
非常有用:
(emit-form (analyze '(let [a 1 a a] a)))
;=> (let* [a 1 a a] a)
(emit-hygienic-form (analyze '(let [a 1 a a] a)))
;=> (let* [a__#0 1 a__#1 a__#0] a__#1)
在一天结束时,macroexpand-1
macroexpand-all
emit-form
和emit-hygienic-form
对于调试clojure宏非常有用。