Макросы, перебирающие неопределенные символы - PullRequest
3 голосов
/ 07 августа 2011

При многократном применении макроса с другим макросом голые символы не вставляются в текущий контекст:

(defmacro ty [type]
  `(deftype ~type []))

(defmacro empties [& args]
  (doseq [arg args]
    `(ty ~arg))
  )

(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)


(derive ::Person ::Base)
(derive ::Animal ::Base)
(ty Me)
(prn ::Me)
(prn Me)
(empties Empty)
(prn ::Empty)
(prn Empty)

Последняя строка дает: «Невозможно разрешить символ: Пусто в этом контексте», хотя при использовании прямой макросы это работает. Любой способ решить это? Если можно без eval, было бы намного лучше.

Ответы [ 2 ]

5 голосов
/ 07 августа 2011
(defmacro empties [& args]
  (doseq [arg args]
    `(ty ~arg)))

(empties Base Person Animal)
;equivalent to:
;(ty Base)
;(ty Person)
;(ty Animal)

Это неправильно. Ваш empties вызов означает, что функция расширения макроса для empties получает в качестве аргументов символы Base, Person и Animal. Затем он оценивает вызов макроса ty для каждого, но ничего не возвращает, так как doseq всегда возвращает ноль. Итак, расширенный код этого вызова empties равен нулю. Вам нужно вернуть одну форму из вашей макрофункции. Вы должны обернуть несколько форм в do и фактически вернуть все подчиненные формы к этому:

(defmacro empties [& args]
  `(do ~@(map (fn [arg]
               `(ty ~arg))
              args)))
2 голосов
/ 08 августа 2011

FWIW, я предпочитаю писать решение @ Сванте как

(defmacro empties [& args]
  (cons `do
        (for [arg args]
          `(ty ~arg))))

, что также довольно близко к структуре вашего doseq подхода.

...