【问题标题】:How to expand macro within other macro's scope (trying to debug a macro)如何在其他宏的范围内扩展宏(尝试调试宏)
【发布时间】:2014-07-25 11:32:13
【问题描述】:

这是我能做的最简单的例子:

(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))

我有什么方法可以扩展嵌套宏吗? 这对我调试特定的错误很有帮助。

【问题讨论】:

    标签: macros clojure


    【解决方案1】:

    你关注macroexpand-all

    (use 'clojure.walk)
    (macroexpand-all '(printer (adder 1)))
    ;(clojure.core/println (clojure.core/inc 1))
    

    【讨论】:

    • 非常感谢!谢谢你,我确实调试了我的错误:)
    【解决方案2】:

    感谢您接受我的回答,我很高兴它有所帮助。我忘了补充一点,如果你想完全扩展编译器看到的内容,你可以利用 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-formemit-hygienic-form 对于调试 clojure 宏都很有用。

    【讨论】:

    • 干杯 =) 将来可能会派上用场。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多