【问题标题】:Clojure Macro ExpansionClojure 宏扩展
【发布时间】:2011-05-13 01:36:09
【问题描述】:

我正在研究一个宏,我想弄清楚如何避免某些形式的扩展,以下面和宏为例,

(defmacro and ([] true) ([x] x) ([x & next] `(let [and# ~x] (if and# (and ~@next) and#))))

展开时,

(mexpand-all '(and 1 2 3))

成为,

(let* [and__973__auto__ 1] (if and__973__auto__ (let* [and__973__auto__ 2] (if and__973__auto__ 3 and__973__auto__)) and__973__auto__))

在这种情况下,我需要做的是阻止 let 扩展为 let*。

【问题讨论】:

    标签: macros clojure lisp


    【解决方案1】:

    嗯?目前尚不清楚您所说的“停止”let 的扩展是什么意思。 let 是 clojure.core 中定义的宏,编译器对此一无所知:它只理解 let*。如果您的宏扩展为 let (不知何故)拒绝进一步扩展,它将无法编译。

    如果您只想单独检查宏的输出,而不用担心递归扩展它,您应该使用macroexpandmacroexpand-1 而不是这个mexpand-all。我不知道mexpand-all 来自哪里,但是当我需要类似的东西时,我会使用clojure.walk/macroexpand-all

    【讨论】:

    • 我想要做的是递归地扩展除了 let 表单之外的所有内容。顺便说一句,mexpand 来自 contrib macro-utils
    • 我也试图阻止某些表单扩展。我想解释一下为什么这个问题有权存在。就我而言,我正在尝试使用 clojure 宏扩展作为从非 clojure lisp 到另一个非 clojure lisp 的转换器。它工作得很好,除了源 lisp 语法与 clojure 的内置宏发生冲突的一些极端情况。
    【解决方案2】:

    递归宏扩展的工作原理是重复扩展表单,直到没有宏可扩展。这意味着,如果您想递归地扩展宏,但忽略某些形式,则必须编写自己的自定义扩展器,或查找其他人的。

    这是一个简单的例子:

    (defn my-expander [form]
        (cond (not (list? form)) (mexpand-1 form)
            (= (first form) 'let) form
               :else (map my-expander (mexpand-1 form))))
    

    如果我犯了任何错误,请原谅我。我使用 Scheme 和 CL 比使用 Clojure 更强大。

    --编辑-- 请注意,上述函数也不会扩展 let 语句的子形式。

    【讨论】:

      【解决方案3】:

      使用macroexpand-1 执行单级宏扩展。

      加载and 宏后,这个表达式:

      user=> (macroexpand-1 '(and 1 2 3))
      

      产量:

      (clojure.core/let [and__1__auto__ 1] (if and__1__auto__ (clojure.core/and 2 3) and__1__auto__))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-21
        • 2011-09-18
        • 2011-06-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多