在Clojure中,一个表达式的结果可以作为(def)的第一个参数吗?

问题描述 投票:0回答:1

我的最终目标是用一个宏来生成这段代码,其中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,而是一个表达式并抛出一个错误。

clojure compiler-errors macros lisp
1个回答
2
投票
(defmacro mirror [val] `(def ~(symbol val) ~val))

0
投票

如果 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.

© www.soinside.com 2019 - 2024. All rights reserved.