我最近开始学习 clojure,正在阅读 The Joy of Clojure 以掌握它。我有一个关于宏章节 (8) 中的代码段的问题,第 166 页
(defmacro domain [name & body]
`{:tag :domain, ;`
:attrs {:name (str '~name)}, ;'
:content [~@body]})
据我了解,
body
是一个类似序列的结构,除了第一个参数之外的所有参数。如果是这样,在第三行中,我们为什么要取消引用拼接( ~@
)并再次将值放入向量中。为什么不做 ~body
而不是 [~@body]
?有什么不同?我很抱歉,但我发现很难掌握整个宏(来自 python)。
编辑:经过一些实验,我发现这有效,
(defmacro domain2 [name & body]
`{:tag :domain, ;`
:attrs {:name (str '~name)}, ;'
:content '~body})
连同我从 Joost 的回答中得到的结果,我想我知道这里发生了什么。
body
被表示为一个列表,所以如果我不放 '
前面~body
, clojure 将尝试对其进行评估。user=> (domain "sh" 1 2 3)
{:content [1 2 3], :attrs {:name "sh"}, :tag :domain}
user=> (domain2 "sh" 1 2 3)
{:content (1 2 3), :attrs {:name "sh"}, :tag :domain}
最佳答案
我认为答案在于这个宏的意图。
快速查看提到的页面,似乎这个想法是使用 map 为域创建数据结构。选择的结构与 clojure.xml 库使用的结构相同。
确实,emit 函数会在您的代码和书中的代码中产生相似的结果,但是由于 clojure.xml 中的函数 parse 生成了一个带有矢量内容的 map ,因此最好在这里执行相同的操作,以便不要破坏依赖相同结构的其他代码。在这里也使用结构体以与 clojure.xml 保持一致可能是个好主意,例如现在 (content (domain ...))
不起作用。
考虑到一般的数据结构,我发现在这里使用像向量这样的索引序列是个好主意,因为它可以说例如 ((:content domain-item) 1)
访问第二项内容。更不用说子序列等。
关于macros - 在 clojure 宏中取消引用拼接并包装在向量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5770127/