我正在研究一个宏,我正在试图弄清楚如何避免某些形式的扩展,例如采取以下和宏,
(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 *。
答案 0 :(得分:5)
咦?目前尚不清楚“停止”let
的扩展意味着什么。 let
是clojure.core中定义的宏,编译器对此一无所知:它只能理解let*
。如果您的宏扩展为let
(以某种方式)拒绝进一步扩展,则无法编译。
如果您想单独检查宏的输出,而不必担心递归扩展它,则应使用macroexpand
或macroexpand-1
代替此mexpand-all
。我不知道mexpand-all
来自哪里,但当我需要这样的东西时,我会使用clojure.walk/macroexpand-all
。
答案 1 :(得分:4)
递归宏扩展通过重复扩展表单直到没有要扩展的宏来工作。这意味着如果你想以递归方式扩展宏,但忽略某些形式,你必须编写自己的自定义扩展器代码,或者找到别人的代码。
这是一个简单的例子:
(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强得多。
- Edit-- 请注意,上述函数也不会扩展let语句的子表单。
答案 2 :(得分:1)
使用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__))