Macros 在clojure中,当使用递归实现宏时,如何进行代码模板化
我试图实现一个宏,以递归方式将中缀列表转换为前缀列表。我遇到如下问题:Macros 在clojure中,当使用递归实现宏时,如何进行代码模板化,macros,clojure,Macros,Clojure,我试图实现一个宏,以递归方式将中缀列表转换为前缀列表。我遇到如下问题: ;;this works (defmacro recursive-infix [form] (list (second form) (first form) (if (not (seq? (nth form 2))) (nth form 2) (recursive-infix (nth form 2))))) ;;this doesn't work (defmac
;;this works
(defmacro recursive-infix [form]
(list (second form) (first form)
(if (not (seq? (nth form 2)))
(nth form 2)
(recursive-infix (nth form 2)))))
;;this doesn't work
(defmacro my-recursive-infix [form]
`(~(second form) ~(first form)
(if (not (seq? ~(nth form 2)))
~(nth form 2)
(my-recursive-infix ~(nth form 2)))))
(macroexpand '(recursive-infix (10 + 10)))
;;get (+ 10 10)
(macroexpand '(my-recursive-infix (10 + 10)))
;;get (+ 10 (if (clojure.core/not (clojure.core/seq? 10)) 10 (user/my-recursive-infix 10)))
(recursive-infix (10 + 10))
;;get 20
(my-recursive-infix (10 + 10))
;;Don't know how to create ISeq from: java.lang.Integer [Thrown class java.lang.IllegalArgumentException]
问题在哪里?如何使用代码模板正确定义宏
另外,我把代码改成了这个,它还能用,为什么?有什么区别
(defmacro my-recursive-infix [form]
(if (not (seq? (nth form 2)))
`(~(second form) ~(first form) ~(nth form 2))
`(~(second form) ~(first form) (my-recursive-infix (nth form 2)))))
在原始版本中,
(if(not…)
检查是在编译时进行的;而是将其包含在扩展代码中。所以这里有一个最小的改变,可以让它表现得像你想要的一样-它实际上和原来的一样,但是“翻转”引用的和没有引用的
(defmacro my-recursive-infix [form]
(let [third (nth form 2)]
`(~(second form) ~(first form)
~(if (not (seq? third))
third
`(my-recursive-infix ~third)))))
但是,使用解构提前提取表单片段比就地提取表单片段要好一些:
(defmacro my-recursive-infix [form]
(let [[x op y] form]
`(~op ~x ~(if (not (seq? y))
y
`(my-recursive-infix ~y)))))
实际上,更好的方法是将非递归的大小写移到外部,以便(a)它适用于文字数字,(b)代码看起来更像它扩展到的:
(defmacro my-recursive-infix [form]
(if-not (seq? form)
form
(let [[x op y] form]
`(~op ~x (my-recursive-infix ~y)))))
这与将“if block”放入backquote的绑定范围有什么关系吗?非常感谢@amalloy-这确实为我提供了一种解决问题()的不那么复杂的方法,但我试图理解最后一个代码块中的确切步骤。在这种情况下递归工作正常吗?我以
形式传递(1+2+3),但它只返回前两个操作数的和。另外,我认为seq?
是检查重复出现的y
值是否是确定是否再次出现的有效形式,对吗?