我的最终目标是用一个宏来生成这段代码,其中word可以是任何字符串(没有空格)。
=> (def word "word")
这是我目前所做的. 它可以编译,但不能运行。
=> (defmacro mirror [val] `(def (symbol val) val))
预期的行为。
=> (mirror "michael")
=> (mirror "jackson")
=> michael
"michael"
=> jackson
"jackson"
实际行为:
=> (mirror "michael")
Syntax error compiling def at (/tmp/form-init2235651799765014686.clj:1:25).
First argument to def must be a Symbol
据我所知 (def)
期待一个Symbol作为它的第一个参数,而这个Symbol就是 (symbol val)
应该返回。我猜测编译器是在检查 (def)
的参数类型,所以它看到的不是一个Symbol,而是一个表达式并抛出一个错误。
(defmacro mirror [val] `(def ~(symbol val) ~val))
如果 val
被期望是一个字符串文字,akond的解决方案就足够了。
如果你想使用字符串生成的表达式,就像amalloy在他的评论中那样,你可以写。
(defmacro mirror [exp] (let [val (eval exp)] `(def ~(symbol val) ~val)))
用amalloy的例子,我们有:
=> (def module-name "foo")
#'user/module-name
=> (mirror (str module-name "-test"))
#'user/foo-test
=> foo-test
"foo-test"
这个宏 "在编译时 "对表达式进行评估。这意味着你不能在它里面使用局部变量(如 (let [suffix "-test"] (mirror (str module-name suffix)))
fails)。) 要在 "运行时 "评估它,你可以写。
(defmacro mirror [exp] `(let [~'val ~exp] (eval `(def ~(symbol ~'val) ~~'val))))
或者,你可以避免使用宏和 def
并使用 intern
.