clojure宏评估
由于对clojure及其宏的了解和熟悉,我给自己设定了一个任务,即编写一个宏,从诸如“abc”之类的字符列表中生成所有长度为“n”的字符串。因此,对于n=2,输出应为“aa”“ab”“ac”“ba”“bb”“bc”“ca”“cb”“cc”。我从以下函数作为模板开始: (定义mkstr[n v](表示[i v j v](str i j)))。在for binding中重复“v”,并创建多少个var作为“n”的函数;在这种特殊情况下:2 在阅读了“quote”“unquote”等相关内容后,在阅读了一篇关于宏的优秀在线教程、多次尝试和错误以及一些简单的运气之后,我成功地生成了以下函数和宏,无论“n”的值是多少,它们都能提供所需的输出。真正困难的部分是生成“for”绑定所需的可变数量的代码clojure宏评估,clojure,macros,eval,Clojure,Macros,Eval,由于对clojure及其宏的了解和熟悉,我给自己设定了一个任务,即编写一个宏,从诸如“abc”之类的字符列表中生成所有长度为“n”的字符串。因此,对于n=2,输出应为“aa”“ab”“ac”“ba”“bb”“bc”“ca”“cb”“cc”。我从以下函数作为模板开始: (定义mkstr[n v](表示[i v j v](str i j)))。在for binding中重复“v”,并创建多少个var作为“n”的函数;在这种特殊情况下:2 在阅读了“quote”“unquote”等相关内容后,在阅读了
(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”才起作用?诚然,它是可用的,但感觉有些不对劲 您的宏返回一个带引号的表单,这就是为什么当您将它传递给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))))
这听起来像是您想要的,尽管我承认我不明白您为什么希望在“编译时”和运行时发生这种情况。谢谢您的回答。它消除了对宏编写的一些误解,但也展示了如何将常规函数代码与生成的代码混合使用,反之亦然。经过进一步的实验,我意识到auto gensym似乎是多么耗时。