Unquote-сплайс и перенос в векторе в макросе clojure - PullRequest
4 голосов
/ 24 апреля 2011

Я недавно начал изучать clojure и читаю Радость Clojure , чтобы разобраться с ней.У меня есть вопрос, касающийся сегмента кода в главе (8) Macros , на стр. 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})

и наряду с результатами, полученными из ответа Джоста, я думаю, что я знаю, что здесь происходит.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}

Ответы [ 2 ]

2 голосов
/ 23 мая 2011

Я думаю, что ответ заключается в намерении этого макроса.

Быстро просматривая упомянутую страницу, кажется, что идея состоит в том, чтобы создать структуру данных для домена, используя карту. Выбранная структура идентична используемой библиотекой clojure.xml.

Это правда, что функция emit будет давать похожие результаты как с вашим кодом, так и с кодом из книги, но так как функция parse из clojure.xml создает карту с содержимым в векторе, лучше сделать то же самое здесь , чтобы не нарушать другой код, опираясь на ту же структуру. Было бы неплохо также использовать здесь структуру, чтобы она соответствовала clojure.xml, как, например, теперь (content (domain ...)) не работает.

Думая о структурах данных в целом, я считаю хорошей идеей использовать здесь индексированную последовательность, такую ​​как вектор, поскольку это позволяет, например, сказать ((:content domain-item) 1) для доступа ко второму элементу контента. Не говоря уже о подпоследовательностях и т. Д.

1 голос
/ 24 апреля 2011

Вы совершенно правы; ~ body уже является последовательностью, поэтому, если нет необходимости гарантировать, что: content является вектором (а не просто чем-то, что может быть найдено), выражение [~ @ body] можно заменить просто ~ body.

...