【问题标题】:Clojure - How to make my macro expand before system macros?Clojure - 如何让我的宏在系统宏之前扩展?
【发布时间】:2011-06-26 10:49:38
【问题描述】:

如果我这样做,例如:

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

失败是因为reify 看到的是(qqq) 而不是(toString [this] "Qqq")

usual solution 是一个用我自己的东西包装“reify”调用的宏,但它更长且更具侵入性。

如何让我的宏比通常的宏更强大?

期待类似:

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

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

【问题讨论】:

  • 很确定 Clojure 中没有这样的机制。
  • @Brian Carper,但我怀疑expand-first 可以在外部实现(后来包含在 Clojure 中)。正在尝试这样做。

标签: macros clojure


【解决方案1】:

有一个读取器宏可以在读取时(在宏扩展时间之前)评估事物..

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

我从来没有在“真实”代码中看到过这种情况,我想大多数人会认为这是一种 hack,但如果你需要它,它就在那里。

【讨论】:

  • 最短的版本,没有额外的依赖。看起来不错。什么陷阱/#= 通常用于什么/
【解决方案2】:

这将起作用:

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

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

(reifyx 'Object (qqq))

我找到了apply-macro。我试过了,但它似乎坏了。我从apply-macro 中收集到的最重要的一点是,它使用eval 解决了问题,就像我一样。

【讨论】:

  • CompilerException Unable to resolve symbol: toString in this context
  • 固定代码是(eval `(reify Object ~(macroexpand `(qqq)))) 如果我经常使用qqq,所有这些“宏扩展”都会一遍又一遍地重复。有没有更好的解决办法?
  • 哦,对不起。我忘了提。 qqq 应该是一个返回列表而不是宏的函数。
【解决方案3】:

强制给定用户宏首先展开的宏(需要clojure.walk):

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

谁知道如何让它变得更好?

【讨论】:

  • prewalkpostwalk? macroexpand-allmacroexpand?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多