Clojure 评估宏的参数

Clojure evaluate argument of macro

我正在尝试编写一个为 core.match 宏生成模式的宏。

(defmacro match2
  [state i predecessor]
  `(match ~[state]
          [(~(vec (concat (repeat i '_)
                           predecessor
                           '(& r)))
            :seq)] ~i
          :else false))

如果我直接将它与硬编码 predecessor:

一起使用,效果很好
(match2 ["B"] 0 ["B"]) ; 0

到目前为止一切都很好,但是如果我尝试使用函数调用传递 predecessor

(match2 ["B"] 0 ((fn [] ["B"]))) ; AssertionError Invalid list syntax [] in (fn [] ["B"])

问题在于,因为 match2 是一个宏,clojure 不会评估函数调用,只会按原样传递表单。未计算的形式然后转到 core.match(再次未计算,因为 core.match 本身是一个宏)并且 core.match 抛出异常,因为形式不是正确的模式。

如何强制对宏参数求值?或者任何其他解决方法?

我被暗示这通常是用第二个宏完成的,但我的尝试没有产生好的结果。

我看到两个选项。在您的宏中使用 eval。

或者,您可以让您的宏不调用匹配宏。让它调用另一个调用匹配宏的函数。这将强制评估途中匹配。

这里有一篇关于此类问题的好文章:

http://amalloy.hubpages.com/hub/Clojure-macro-writing-macros

core.match 是一个编译器。它将一些形式变成可执行的表达式。它可以处理的形式必须遵守语法,因此断言抛出。作为一个宏,它在……编译时编译。无论您多么努力,都无法让它编译运行时表达式的结果。

即使您设法在编译时评估 (fn [] ["B"]) 以便将值提供给 match,我认为这不是您的目标。您要做的是将匹配项与您的程序逻辑评估的表达式进行匹配。去过那里,很遗憾地说 core.match 是不可能的,D. Nolen 证实了这一点。

不过,matchure 可以做到这一点:在运行时创建匹配函数/表达式,请参阅 fn-match. It is unmaintained AFAIK but just works. I've patched it some time ago to use clj 1.6, here