为什么不能在普通(未引用的)代码中取消引用拼接?

mik*_*era 5 macros clojure quoting

在Clojure中,您可以取消引用拼接值列表以生成代码,例如

(def extra-values [1 2 3 4])

`(+ 100 200 ~@extra-values)
=> (clojure.core/+ 100 200 1 2 3 4)
Run Code Online (Sandbox Code Playgroud)

似乎合乎逻辑的是,相同的方法应该在不带引号的上下文中起作用,例如

(def extra-values [1 2 3 4])

(+ 1000 ~@extra-values)
=> [an error, but one could argue that the answer should be 1010??]
Run Code Online (Sandbox Code Playgroud)

有什么深刻的技术/哲学原因,为什么这不起作用?

ama*_*loy 13

一个简单的原因是

`(+ 100 200 ~@extra-values) 
Run Code Online (Sandbox Code Playgroud)

定义不明确:它是否扩展到

(+ 100 200 1 2 3 4)
Run Code Online (Sandbox Code Playgroud)

或者

(+ 100 200 ~@extra-values)
Run Code Online (Sandbox Code Playgroud)

?如果~@构造在该上下文中是合法的,则两者都是有效的解释.

它还会导致宏观系统出现严重问题.考虑

(defmacro foo [x & args]
  `(list ~x ~(count args)))

(let [data '(1 2 3)]
  (foo "three" ~@data))
Run Code Online (Sandbox Code Playgroud)

怎么foo知道它传递的是什么?它当然不能在编译时扩展它,所以现在unquote-splicing只在一些非引用的上下文中有效.

总的来说,它只是混淆了语言,以适应对核心概念的不理解 - 如果你真的想要取消引用拼接来构建复杂的参数列表,你可以轻松地使用apply类似的东西

(apply + `(100 ~@extra-values 200))
Run Code Online (Sandbox Code Playgroud)