Как передать необязательные аргументы макроса в функцию - PullRequest
3 голосов
/ 13 января 2012

Clojure макро нуб здесь. У меня есть функция с некоторыми необязательными параметрами, например

(defn mk-foo [name & opt]
  (vec (list* name opt)))

давая это:

user> (mk-foo "bar" 1 2 3)
["bar" 1 2 3]

Я пытаюсь написать макрос, который принимает те же необязательные аргументы и передает их прозрачно для вызова mk-foo. Пока у меня есть это:

(defmacro deffoo [name & opt]
  `(def ~name ~(apply mk-foo (str name) opt)))

, который имеет желаемый эффект:

user> (macroexpand '(deffoo bar 1 2 3))
(def bar ["bar" 1 2 3])

Использование apply для выравнивания списка opt кажется неуклюжим. Есть ли идиоматический способ сделать это? Я предполагаю, что ~@ необходим, но я не могу правильно процитировать цитату. Большое спасибо.

1 Ответ

3 голосов
/ 13 января 2012

Ваша интуиция об использовании apply хорошо послужила вам в этом случае.Если у вас есть форма в кавычках `и затем все они указаны в кавычках, это может помочь подумать о том, чтобы переместить без кавычек вниз наименьшую часть или список.Это позволяет избежать использования кода для генерации форм, которые могут быть просто написаны.

user=> (defmacro deffoo [name & opt] `(def ~name [~(str name) ~@opt]))       
#'user/deffoo
user=> (macroexpand '(deffoo "bar" 1 2 3))                            
(def "bar" ["bar" 1 2 3])

и вот с вызовом mk-foo:

(defmacro deffoo [name & opt] `(def ~name (mk-foo ~(str name) ~@opt)))     
#'user/deffoo
user=> (macroexpand '(deffoo "bar" 1 2 3))                                   
(def "bar" (user/mk-foo "bar" 1 2 3))

во втором случае мы перемещаем ~ на один уровень и разрешаем вызов mk-foo оставаться в кавычках и только заключать в кавычки аргументы, необходимые для построения списка параметров (используя splicing-unquote, как вы и предполагали)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...