“透明”的宏可能吗?

时间:2011-08-30 09:09:25

标签: macros clojure common-lisp

我想编写一个包含大量表单的Clojure with-test-tags宏,并在每个deftest表单的名称中添加一些元数据 - 具体来说,将一些内容添加到{{1}我可以使用工具来运行带有特定标记的测试。

:tags的一个明显实现是递归遍历整个身体,在我找到它时修改每个with-test-tags表单。但我最近一直在阅读 Let Over Lambda ,他提出了一个很好的观点:不要自己走代码,只需将代码包装在deftest中,然后让编译器将其转换为您。类似的东西:

macrolet

这有一个明显的问题,即(defmacro with-test-tags [tags & body] `(macrolet [(~'deftest [name# & more#] `(~'~'deftest ~(vary-meta name# update-in [:tags] (fnil into []) ~tags) ~@more#))] (do ~@body))) (with-test-tags [:a :b] (deftest x (...do tests...))) 宏继续以递归方式永久扩展。我可以将其扩展为deftest,从而避免任何进一步的递归扩展,但是我无法将clojure.test/deftest的实例嵌套到标签测试的子组中。

此时,特别是对于像with-test-tags这样简单的事情,看起来自己走代码会更简单。但是我想知道是否有人知道编写宏的技术,它会“略微修改”某些子表达式,而不会永远递归。

对于好奇:我考虑过其他一些方法,比如我有一个编译时deftest - 我设置为上下代码的var,并在我最终看到{时使用该var {1}},但由于每个宏只返回一个扩展,因此下一次调用macroexpand时,它的绑定将不会到位。

修改

我刚才做了一个postwalk实现,虽然它有效但它不尊重binding这样的特殊形式 - 它也会扩展到那些内部。

deftest

(另外,对于common-lisp标签上可能存在的噪音感到抱歉 - 我认为即使只有最小的Clojure经验,你也可以帮助我们处理weirder宏的东西。)

2 个答案:

答案 0 :(得分:5)

答案 1 :(得分:0)

至少使用Common Lisp,您可以简单地给阴影宏起别名。像这样:

(setf (macro-function 'deftest2) (macro-function 'deftest))
(defmacro with-test-tags (etc...)
  `(macrolet ((deftest (etc...)
                 ``(deftest2 ...

Clojure应该有类似的东西。此处讨论了该主题:define a synonym for a Clojure macro。请注意,定义扩展为“ deftest”调用的“ deftest2”宏可能不起作用。

我看到这个答案有点晚了,但是我会在这里张贴给路人。