强制扩展Clojure宏中的表达式

时间:2011-06-19 12:21:32

标签: macros clojure

我正在尝试在defprotocol内使用Stuart Sierra的do-template宏,而Clojure编译器抱怨我正在重新定义do-template - 而不是我想要的:

(defprotocol AProtocol
  (a-method [_])
  (do-template [name]
    `(~(symbol (str name "-method")) [this that])
    foo
    bar
    baz))

这应扩展为:

(defprotocol AProtocol
  (a-method [_])
  (foo-method [this that])
  (bar-method [this that])
  (baz-method [this that]))

问题(我相信)是do-template s表达式传递给未展开的defprotocol。是否有任何方法可以在传递之前对其进行评估?

BTW,do-template实际应该扩展到

(do
  (foo-method [this that])
  (bar-method [this that])
  (baz-method [this that]))

但我已尝试过(使用手动扩展版本)defprotocol与嵌套do一样好。

如何查看do-template的实际扩展?我尝试了(macroexpand '(do-template ...))(macroexpand-1 '(do-template ...))并得到了:

  

(do(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(符号(str foo   “-method”)))(clojure.core / list   (clojure.core /应用   clojure.core / vector(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(引用user / this))   (clojure.core / list(引用   user / that))))))))(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(符号(str bar   “-method”)))(clojure.core / list   (clojure.core /应用   clojure.core / vector(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(引用user / this))   (clojure.core / list(引用   user / that))))))))(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(符号(str baz   “-method”)))(clojure.core / list   (clojure.core /应用   clojure.core / vector(clojure.core / seq   (clojure.core / CONCAT   (clojure.core / list(引用user / this))   (clojure.core / list(引用   用户/那个)))))))))

不容易阅读: - )。

此外,我可能希望thisthat成为 anaphora 并展开给自己:~'this

1 个答案:

答案 0 :(得分:3)

(1)对于do表格,defprotocol不合适。它不会引发错误,但它也不起作用。

(2)你不能以这种方式做你想做的事。 defprotocol是被调用的宏,因此它对如何扩展子表单具有绝对的权威性。

(3)第(2)项提出了一个解决方案,实际上与最近的一个问题相同:定义一个新的宏,比如说with-methods,它取一个方法名列表,然后是无论其他什么样的defprotocol参数,并扩展到一个defprotocol与适当的替换和拼接已经完成,所以defprotocol可以平安扩展,而无需了解你的模板技巧。