2

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

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

如果我直接将它与硬编码的前任一起使用,这很好用:

(match2 ["B"] 0 ["B"]) ; 0

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

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

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

如何强制对宏参数进行评估?或任何其他解决方法?

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

4

2 回答 2

3

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

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

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

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

于 2015-09-28T23:09:41.133 回答
-1

core.match是一个编译器。它将某些形式转换为可执行的表达式。它可以处理的形式必须尊重语法,因此断言抛出。作为一个宏,它在...编译时编译。不管你怎么努力,你都不能让它编译运行时表达式的结果。

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

不过,matchure可以做到这一点:在运行时创建匹配函数/表达式,请参阅fn-match. 它是未维护的 AFAIK,但可以正常工作。前段时间我已经对其进行了修补以使用 clj 1.6,here

于 2015-09-29T15:59:02.293 回答