clojure递归宏定义

时间:2017-12-11 16:49:08

标签: recursion clojure macros

嗨,我正在学习Clojure宏,我正在尝试编写一个将中缀形式转换为前缀形式的宏,如下所示:(9 +(1 * 3))=> (+ 9(* 1 3))

(defn infix [form]
  (list (second form) (first form) (nth form 2)))

(defmacro r-infix [form]
  (if (coll? form)
    (map r-infix (infix form))
    form))

(r-infix (9 + (1 * 2)));;=>ArityException

但是如果按照以下方式定义宏,它可以正常工作:

(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

我在调试第一个例子时遇到一些困难,任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:3)

Clojure中的宏不是"一等公民",这意味着他们不能以数据和功能(非宏)的所有方式使用。

您无法映射宏: - (

因此,第一个示例尝试将宏传递给函数,这会导致无法获取宏值的错误。为了探究为什么我们要与一个足够先进的编译器进行虚构的对话。

  

:hello编译器,请使用此宏并使用它来转换所有这些表达式。

     

足够高级编译器:我试着查看你的宏,并试图评估我何时阅读它,我不知道你想要什么   我传递给这个函数,当我读到它时宏会消失???

     

:哦,对不起,我只想要一些能够列出并改变它的东西。

     

Sufficiently-Advanced-Compiler :这听起来像一个函数: - )

宏是标记有特殊标志的函数,这些标志使它们在读取时运行,并在最终代码准备好运行之前完全完成。这使得在编写编译器时将它们传递给其他不是非常混乱的东西。

这是一种常见的反模式,称为宏传染,其中代码只作为宏编写,因为它需要以某种动态方式调用另一个宏。然后结果是更多的代码被写成一个宏,并且它是一个螺旋式下降。

你的第二种方法显示了这样做的正确方法,其中宏的所有工作都是在普通函数(恰好由宏调用)中完成的,这些函数作为入口点包装在一个瘦的宏层中。当后来某人需要出现并将r-inflix-fn应用于其他东西时,或许是一棵树,那么他们就不必将他们的新代码作为宏来打电话给你。

一般来说,明智地怀疑任何只能通过宏访问

的代码。