clojure宏观评论

时间:2012-12-01 15:30:18

标签: clojure macros eval

被吸引到clojure及其宏的新手,我自己设定了一个编写宏的任务,该宏从字符列表(如“abc”)生成所有长度为'n'的字符串。因此,对于n = 2,输出应为“aa”“ab”“ac”“ba”“bb”“bc”“ca”“cb”“cc”。我开始使用以下函数作为模板: (defn mkstr [n v](for [i v j v](str i j)))。 for绑定中的'v'的重复以及多少vars的创建应该是'n'的函数;在这个具体案例中:2。

在阅读'引用''unquote'等之后,然后按照一个关于宏的优秀在线教程,很多试验和错误,以及一些简单的运气我设法生成以下函数和宏,它提供了所需的输出,无论是什么'n'的值。真正困难的部分是生成'for'绑定所需的可变数量的代码。

(defn mkvars [n] 
"Gives a list of 'n' unique symbols"
(let [vc (repeatedly n #(gensym ))] vc)) 

(defmacro mkcoms [n syms] 
"Generates a list of possible combinations of length 'n' from a string of symbols"
`(let [vs# (mkvars ~n) sy# ~syms  
    forarg# (vec (interleave vs# (repeat ~n sy#)))]
     `(for ~forarg# (str ~@vs#))))

现在我的'真正'问题或缺乏理解是要获得输出我必须这样做: (eval(mkcoms len chars))。为什么这只能使用'eval'?没错,它可以按原样使用,但是它有些不对劲。

1 个答案:

答案 0 :(得分:2)

您的宏返回一个引用的表单,这就是为什么它将它传递给eval时的工作原理。我不明白宏的功能是什么,所以我希望这个解释是你所追求的。

宏应该生成它代表的代码并返回它。您的宏生成引用的表单。如果删除后引用的外层,看起来意图是执行扩展(宏)的代码的一部分而不是结果代码,那么你确实可以在宏扩展时执行:

(defmacro mkcoms [n syms]                                                                                                      
  "Generates a list of possible combinations of length 'n' from a string of symbols"                                           
  (let [vs     (mkvars n)                                                                                                      
        sy     syms                                                                                                            
        forarg (vec (interleave vs (repeat n sy)))]                                                                            
    `(for ~forarg (str ~@vs))))

这听起来像你所追求的,虽然我承认我不明白你为什么要在“编译时”与运行时间发生这种情况。