Macros 在clojure宏中取消拼接和包裹向量
我最近开始学习clojure,我正在阅读《clojure的快乐》来掌握它。我有一个关于宏第(8)章第166页代码段的问题Macros 在clojure宏中取消拼接和包裹向量,macros,clojure,Macros,Clojure,我最近开始学习clojure,我正在阅读《clojure的快乐》来掌握它。我有一个关于宏第(8)章第166页代码段的问题 (defmacro domain [name & body] `{:tag :domain, ;` :attrs {:name (str '~name)}, ;' :content [~@body]}) 据我所知,body是一个类似于序列的结构,除了第一个参数外,它包含所有参数。如果是这样,在
(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}
你说得很对~body已经是一个序列,所以除非需要保证:内容是一个向量(而不仅仅是可以排序的东西),否则[~@body]表达式可以被~body替换。我认为答案在于这个宏的意图 快速查看上面提到的页面,其想法似乎是使用地图为域创建数据结构。选择的结构与clojure.xml库使用的结构相同 确实,emit函数将使用您的代码和本书中的代码生成类似的结果,但是当clojure.xml中的函数parse生成一个向量中包含内容的映射时,最好在这里执行相同的操作,以免破坏依赖相同结构的其他代码。在这里使用struct与clojure.xml保持一致可能是个好主意,例如现在的
(content(domain…)
不起作用
考虑到一般的数据结构,我发现在这里使用一个索引序列(如vector)是一个好主意,因为它可以说例如
(:content domain item)1)
来访问第二项内容。更不用说子序列等了。同样,可以在这里像这样发布本书中的一段代码,对吗?只是需要注意的一点,它是不加引号的拼接,而不是不加引号的拼接-slicing@Nicolas,更新了thanksThanks,但是,如果我将[~@body]
替换为~body
,并执行(域“sh”1 2 3)
,我得到一个java.lang.ClassCastException:java.lang.Integer不能转换为clojure.lang.IFn(无源文件:0)
。调用macroexpand
也会引发相同的错误。您应该对引用的表达式调用macroexpand,否则它将在macroexpand到达它之前进行计算。Macroexpand是一个函数。谢谢Verneri,这很有意义:)