Unquote-splice and wrap in vector in clojure macro

I recently started to learn clojure and read the "Joy" clojure to handle this. I have a question about the code segment in the chapter "Macros" (8), on page 166

(defmacro domain [name & body] `{:tag :domain, ;` :attrs {:name (str '~name)}, ;' :content [ ~@body ]}) 

As I understand it, body is a sequence similar to a structure with all arguments except the first. If so, on the third line, why do we perform unquote-splicing ( ~@ ) and put the values ​​in the vector again. Why not just ~body instead of [ ~@body ] ? What is the difference?

I am very sorry, but it is very difficult for me to understand all the macros (from python).

Edit: After a little experiment, I found that this works,

 (defmacro domain2 [name & body] `{:tag :domain, ;` :attrs {:name (str '~name)}, ;' :content '~body}) 

and along with the results from Joost's answer, I think I know what is going on here. body is represented as a list, and therefore, if I do not put ' before ~body , clojure will try to evaluate it.

 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} 
+4
source share
2 answers

I think the answer lies in the intent of this macro.

Looking quickly at the specified page, the idea seems to be to create a data structure for the domain using a map. The selected structure is identical to that used by the clojure.xml library.

True, the emit function will give similar results with both your code and the code from the book, but since the parse function from clojure.xml creates a map with content in a vector, it’s better to do the same here so as not to break other code based on the same structure. It might also be nice to use a structure to match clojure.xml, since now, for example, (content (domain ...)) not working.

Thinking about data structures in general, I think it is advisable to use an indexed sequence, such as a vector here, because it allows, for example, to say ((:content domain-item) 1) to access the second content element. Not to mention subsequences, etc.

+2
source

You are absolutely right; ~ body is already a sequence, therefore, if there is no need to guarantee that: content is a vector (instead of what can be selected), the expression [~ @body] can be replaced simply by ~ the body.

+1
source

All Articles