【问题标题】:Clojure evaluate argument of macroClojure评估宏的参数
【发布时间】:2015-09-28 22:47:31
【问题描述】:

我正在尝试编写一个为 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

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

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

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

如何强制对宏参数进行评估?还是有其他解决方法?

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

【问题讨论】:

  • 嗯,总有'eval'
  • 我已经更新了我的答案,并提供了一些关于您遇到的问题类型的好读物的链接。我鼓励您不要将当前接受的答案作为这件事的最终决定权,因为它绕过了您遇到的实际问题。

标签: clojure macros pattern-matching core.match


【解决方案1】:

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

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

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

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

【讨论】:

  • 我相信 eval 方法行不通(我试过),因为它只会传递未赋值的(eval 表达式)来匹配。第二种方式,我不确定,但我再次认为它有效,因为当生成的模式走出宏进入函数并被评估时,它们会导致异常(可能归功于下划线和 &)。跨度>
  • 不,您应该在第一次扩展时 eval,然后将其传递给您发出的引用宏调用,eval 本身不会发送到宏中。但是最好使用辅助函数作为中介,这样可以避免这种情况。
  • 要投反对票。这似乎是做作的,我会投票赞成一个可行的例子。和平。
  • @FrançoisDeSerres 关于让宏相互交互这个非常常见的主题有很多文献。我已经将 amalloy 的一个很好的解释联系起来。否决票是不必要的。您的答案不正确,也值得一票。
【解决方案2】:

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

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

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

【讨论】:

  • 我不同意,或者至少我不认为这是 OP 遇到的问题。当让两个宏进行交互并学习通过第二个宏的参数的非评估墙时,这是一个基本且常见的问题。
猜你喜欢
  • 2011-10-21
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多