Macros 为什么可以';你们不能用普通(无引号的)代码解开接头吗?
在Clojure中,您可以取消引用值列表以生成代码,例如Macros 为什么可以';你们不能用普通(无引号的)代码解开接头吗?,macros,clojure,quoting,Macros,Clojure,Quoting,在Clojure中,您可以取消引用值列表以生成代码,例如 (def extra-values [1 2 3 4]) `(+ 100 200 ~@extra-values) => (clojure.core/+ 100 200 1 2 3 4) 同样的方法应该适用于无引号的上下文,这似乎是合乎逻辑的 (def extra-values [1 2 3 4]) (+ 1000 ~@extra-values) => [an error, but one could argue that
(def extra-values [1 2 3 4])
`(+ 100 200 ~@extra-values)
=> (clojure.core/+ 100 200 1 2 3 4)
同样的方法应该适用于无引号的上下文,这似乎是合乎逻辑的
(def extra-values [1 2 3 4])
(+ 1000 ~@extra-values)
=> [an error, but one could argue that the answer should be 1010??]
有没有什么深层次的技术/哲学原因可以解释为什么这样做行不通?一个简单的原因就是这样
`(+ 100 200 ~@extra-values)
定义不清:是否扩展到
(+ 100 200 1 2 3 4)
或
(+ 100 200 ~@extra-values)
??如果~@
结构在该上下文中是合法的,则这两种解释都是有效的
这也在宏观体系中造成了严重问题。考虑
(defmacro foo [x & args]
`(list ~x ~(count args)))
(let [data '(1 2 3)]
(foo "three" ~@data))
foo
如何知道传递的参数是什么?它当然不能在编译时扩展它,所以现在unquote拼接只在一些未引用的上下文中有效
总的来说,它只是把语言弄得一团糟,以适应对核心概念理解不足的情况——如果您真的想取消引用splice来构建一个复杂的参数列表,您可以很容易地使用apply
,例如
(apply + `(100 ~@extra-values 200))
syntax quote
、unquote
和unquote拼接的要点是帮助开发人员编写宏
例如,如果没有syntax quote
和unquote
,您将不得不编写
user=> (list :a extra-values)
(:a [1 2 3 4])
而不是:
user=> `(:a ~extra-values)
(:a [1 2 3 4])
user=> (concat `(+ 100 200) extra-values)
(clojure.core/+ 100 200 1 2 3 4)
在前一种情况下,读者(人类读者-而不是repl)更难理解结果形式的外观,而后一种情况则保持结果形式的“形状”
那么,如果我们不使用向量
[1 2 3 4]
而希望将额外值的内容作为元素拼接到结果表单中,该怎么办?我们需要unquote拼接
,以便编写:
user=> `(+ 100 200 ~@extra-values)
(clojure.core/+ 100 200 1 2 3 4)
而不是:
user=> `(:a ~extra-values)
(:a [1 2 3 4])
user=> (concat `(+ 100 200) extra-values)
(clojure.core/+ 100 200 1 2 3 4)
同样,unquote拼接
版本允许代码在计算代码时与结果形式的“形状”相似,而在后一版本中,“形状”在apply
和list
的噪音中丢失
这两个例子都很简单,但是语法引号
和朋友们在编写更复杂的宏时,真的有了自己的想法
回到你的问题,为什么你不能写(+1000~@额外值)
?我们在apply
中已经有了该功能(还有一些限制):
可能是为了避免将语言的“元”特性与语言的“正常”特性混为一谈:)回答得好,我喜欢这些例子。谢谢