Clojure - How to make my macro expand before syste

2020-03-14 15:18发布

If I do, for example:

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

it fails because of reify sees (qqq) instead of (toString [this] "Qqq").

The usual solution is a macro that wraps "reify" call with my own thing, but it is longer and more intrusive.

How to make my macros stronger that usual macros to be expanded first?

Expecting something like:

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

or

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

3条回答
叛逆
2楼-- · 2020-03-14 16:02

There is a reader-macro to evaluate things at read-time (before macro-expansion time)..

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

I've never seen this done in "real" code, and I think most people would consider it a hack, but it's there if you need it.

查看更多
混吃等死
3楼-- · 2020-03-14 16:05

This will work:

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

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

(reifyx 'Object (qqq))

I found an apply-macro. I tried it, but it seems to be broken. The most important thing I gleaned from looking at apply-macro was that it solved the problem using eval just as I have.

查看更多
够拽才男人
4楼-- · 2020-03-14 16:11

The macro that forces given user macros to expand first (requires clojure.walk):

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

Who has ideas how to make it better?

查看更多
登录 后发表回答