Macros Clojure宏扩展
我正在研究一个宏,我试图找出如何避免某些形式的扩展,以下面的和宏为例Macros Clojure宏扩展,macros,clojure,lisp,Macros,Clojure,Lisp,我正在研究一个宏,我试图找出如何避免某些形式的扩展,以下面的和宏为例 (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* [a
(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*哈?不清楚“停止”
let
扩展是什么意思let
是clojure.core中定义的宏,编译器对此一无所知:它只理解let*
。如果宏扩展为一个let
,而它(不知何故)拒绝进一步扩展,则它将无法编译
如果只想单独检查宏的输出,而不必担心递归扩展,则应使用
macroexpand
或macroexpand-1
而不是使用此mexpand all
功能。我不知道mexpand all
从何而来,但当我需要类似的东西时,我会使用clojure.walk/macroexpand all
使用macroexpand-1
执行单级宏扩展
加载和宏后,此表达式:
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__))
递归宏扩展的工作原理是反复扩展窗体,直到没有宏可扩展为止。这意味着,如果要递归地展开宏,但忽略某些表单,则必须编写自己的自定义扩展程序,或者查找其他人的自定义扩展程序
下面是一个简单的例子:
(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语句的子窗体。我试图做的是递归展开除let窗体之外的所有内容。顺便说一句,mexpand也来自contrib宏utilsI,我试图阻止某些形式的扩展。我想解释一下为什么这个问题有权存在。在我的例子中,我尝试使用clojure宏扩展作为从非clojure lisp到另一个非clojure lisp的传输程序。它工作得相当好,除了一些源lisp语法与clojure的内置宏冲突的情况。