Recursion clojure递归宏定义
您好,我正在学习Clojure宏,我正在尝试编写一个宏,将中缀形式转换为前缀形式,如下所示:(9+(1*3))=>(+9(*13)) 但如果按以下方式定义宏,则效果良好:Recursion clojure递归宏定义,recursion,clojure,macros,Recursion,Clojure,Macros,您好,我正在学习Clojure宏,我正在尝试编写一个宏,将中缀形式转换为前缀形式,如下所示:(9+(1*3))=>(+9(*13)) 但如果按以下方式定义宏,则效果良好: (defn infix [form] (list (second form) (first form) (nth form 2))) (defn r-infix-fn [form] (if (coll? form) (map r-infix-fn (infix form)) form)) (de
(defn infix [form]
(list (second form) (first form) (nth form 2)))
(defn r-infix-fn [form]
(if (coll? form)
(map r-infix-fn (infix form))
form))
(defmacro r-infix [form]
(r-infix-fn form))
(r-infix (9 + (1 * 2)));;=>11
我在调试第一个示例时遇到了一些困难,有人能帮我吗?Clojure中的宏不是“一流公民”,这意味着它们不能以数据和函数(不是宏)可以使用的所有方式使用 无法映射宏:-( 因此,第一个示例尝试将宏传递给函数,这会导致无法获取宏值的错误。为了探究原因,让我们与足够高级的编译器进行一次虚拟对话 你好,编译器,请用这个宏来转换所有这些表达式 足够高级的编译器:我试图查看您的宏,当我阅读它时,它试图计算,我不确定您想要什么 如果我要传递给这个函数,宏在我读取时会消失 我:哦,对不起,我只是想要一个列表,然后改变它 足够高级的编译器:听起来像函数:-) 宏是用特殊标志标记的函数,该标志使它们在读取时运行,并在最终代码准备运行之前完全完成。这使得在编写编译器时,将它们传递给其他本身不是宏的东西变得非常混乱 其效果是一种称为宏传染的常见反模式,其中代码作为宏编写,只是因为它需要以某种动态方式调用另一个宏。结果,更多的代码被写成宏,这是一个向下的螺旋 第二种方法显示了正确的方法,其中宏的所有工作都是在普通函数(恰好由宏调用)中完成的,这些函数作为入口点包装在一个薄宏层中。当稍后有人需要将r-inflix-fn应用于其他东西时,可能是树,那么他们就不必为了调用您的宏而将新代码变成宏
一般来说,明智的做法是怀疑任何只能通过宏访问的代码。潜在相关:似乎是一个几乎完全相同的“异地复制”:答案很好,但它忽略了一些重要内容:第一个示例不会导致“宏值”错误;事实上,它确实导致了一个arity异常。你能解释一下吗?@Carcigenicate我想这是因为第一个例子不是通过它的var调用宏,而是通过它自身的本地别名:
(defmacro foo[]body)
扩展为类似(def^:macro foo(fn foo[&form&env]body))
,它是“内部的”foo
,由fn
命名的一个,它被传递到map
。它没有标记为宏(因为它是本地的),并且需要两个额外的“隐藏”参数,因此算术不匹配。@amalloy Mm,很有趣。当我在REPL中胡闹时,我想我试着给它3个参数。哦,好吧。
(defn infix [form]
(list (second form) (first form) (nth form 2)))
(defn r-infix-fn [form]
(if (coll? form)
(map r-infix-fn (infix form))
form))
(defmacro r-infix [form]
(r-infix-fn form))
(r-infix (9 + (1 * 2)));;=>11