我正在尝试在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(引用 用户/那个)))))))))
不容易阅读: - )。
此外,我可能希望this
和that
成为 anaphora 并展开给自己:~'this
。
答案 0 :(得分:3)
(1)对于do表格,defprotocol不合适。它不会引发错误,但它也不起作用。
(2)你不能以这种方式做你想做的事。 defprotocol是被调用的宏,因此它对如何扩展子表单具有绝对的权威性。
(3)第(2)项提出了一个解决方案,实际上与最近的一个问题相同:定义一个新的宏,比如说with-methods
,它取一个方法名列表,然后是无论其他什么样的defprotocol参数,并扩展到一个defprotocol与适当的替换和拼接已经完成,所以defprotocol可以平安扩展,而无需了解你的模板技巧。