2

被 clojure 及其宏所吸引和新手,我为自己设定了编写一个宏的任务,该宏从诸如“abc”之类的字符列表中生成所有长度为“n”的字符串。所以对于 n=2,输出应该是“aa”“ab”“ac”“ba”“bb”“bc”“ca”“cb”“cc”。我从以下函数作为模板开始:(defn mkstr [nv] (for [ivjv] (str ij)))。for绑定中'v'的重复以及创建多少个变量应该是'n'的函数;在这种特定情况下:2。

在阅读了'quote''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' 起作用?的确,它可以按原样使用,但感觉有些不对劲。

4

1 回答 1

2

Your macros is returning a quoted form, which is why it works when you pass it to eval. I'm not understanding what the purpose of the macro is over the function, so I hope this explanation is what you're after.

A macro is supposed to generate the code it represents and return it. Your macro generates a quoted form. If you remove the outer layer of back-quoting, which looks like the intention is to be part of the code doing the expansion (the macro) and not the resultant code, you do get the execution at macro-expansion-time:

(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))))

This sounds like what you're after, though I admit I don't understand why you want this to happen at 'compile time' vs run-time.

于 2012-12-01T15:47:58.843 回答