Clojure - Как заставить мой макрос расширяться до системных макросов? - PullRequest
8 голосов
/ 13 февраля 2011

Если я сделаю, например:

(defmacro qqq [] '(toString [this] "Qqq"))
(reify Object (qqq))

, произойдет сбой, потому что reify видит (qqq) вместо (toString [this] "Qqq").

обычное решение это макрос, который оборачивает вызов "reify" моей собственной вещью, но он длиннее и более навязчив.

Как сделать мои макросы сильнее, чем обычные макросы, которые будут расширены первыми?

Ожидаетсячто-то вроде:

(defmacro ^{:priority 100500} qqq [] '(toString [this] "Qqq"))
(reify Object (qqq))

или

(defmacro qqq [] '(toString [this] "Qqq"))
(expand-first #{qqq} (reify Object (qqq)))

Ответы [ 3 ]

7 голосов
/ 02 марта 2011

Существует макрос для чтения, который оценивает вещи во время чтения (до времени расширения макроса) ..

(defn qqq [] '(toString [this] "Qqq"))
(reify Object #=(qqq))

Я никогда не видел, чтобы это было сделано в "реальном" коде, и я думаю, что большинство людей сочли бы это взломом, но оно есть, если вам это нужно.

1 голос
/ 14 февраля 2011

Макрос, который заставляет заданные пользовательские макросы расширяться в первую очередь (требуется clojure.walk):

(defmacro expand-first [the-set & code] 
 `(do ~@(prewalk 
  #(if (and (list? %) (contains? the-set (first %)))
  (macroexpand-all %)
  %) code)))

У кого есть идеи, как его улучшить?

0 голосов
/ 15 февраля 2011

Это будет работать:

(defn reifyx [x y]
  (eval `(reify ~x ~y)))

(defn qqq [] '(toString [this] "Qqq"))

(reifyx 'Object (qqq))

Я нашел apply-macro .Я попробовал, но, похоже, сломан.Самая важная вещь, которую я обнаружил, глядя на apply-macro, заключалась в том, что она решила проблему, используя eval, как и я.

...