Clojure宏难题:在宏args中扩展序列

jk.*_*jk. 4 clojure

这不是我的"生产代码",而是为了说明目的而简化问题.此外,这个问题的标题是误导性的,因为它让人想起〜@扩展,我理解,这可能不一定是问题.如果可以,请建议更好的问题标题.

给定一个具有以下形式的宏:

(defmacro my-add [x & ys] `(+ ~x ~@ys))
Run Code Online (Sandbox Code Playgroud)

现在让我们说我们有一个清单:

(def my-lst '(2 3))
Run Code Online (Sandbox Code Playgroud)

现在我想要一个使用my-add的函数,我可以将my-lst传递给arg,即

(call-my-add 1 my-lst)
Run Code Online (Sandbox Code Playgroud)

我以一种看似明显的方式定义函数:

(defn call-my-add [x ys]
    (apply my-add (cons x ys)))
Run Code Online (Sandbox Code Playgroud)

但:

java.lang.Exception: Can't take value of a macro: #'user/call-my-add (repl-1:60)
Run Code Online (Sandbox Code Playgroud)

我已经尝试了各种各样的狂野技巧来使用call-my-add函数来使用evals,apply,甚至将call-my-add定义为宏,但它们都提供类似的ClassCastExceptions.

这有什么办法吗?

ama*_*loy 6

不会.宏不会,也不会,永远不会访问其参数中包含的实际运行时值,因此无法将它们拼接到扩展中.他们得到的只是你传给他们的符号,在这种情况下my-list."解决这个问题的方法"是将my-add定义为一个函数,然后(可选)有一个宏来调用该函数以生成其代码.

我写了一篇关于这个半近期的博客文章,你可能会觉得很有启发性.

如果你愿意,你可以用evals做到这一点,但几乎在每种情况下这都是一个可怕的想法:

(let [my-list '(1 2)]
  (eval `(my-add 5 ~@my-list)))
Run Code Online (Sandbox Code Playgroud)