I am trying to use Stuart Sierra's do-template
macro inside a defprotocol
and the Clojure compiler complains that I am redefining do-template
-- not what I intend:
(defprotocol AProtocol
(a-method [_])
(do-template [name]
`(~(symbol (str name "-method")) [this that])开发者_如何学C
foo
bar
baz))
This should expand to:
(defprotocol AProtocol
(a-method [_])
(foo-method [this that])
(bar-method [this that])
(baz-method [this that]))
The problem (I believe) is that the do-template
s-expression is getting passed to defprotocol
unexpanded. Is there any way to cause it to evaluate before being passed?
BTW, do-template
should actually expand to
(do
(foo-method [this that])
(bar-method [this that])
(baz-method [this that]))
but I already tried that (with a hand-expanded version) and defprotocol
is fine with the nested do
.
How can I see the actual expansion of the do-template
? I tried both (macroexpand '(do-template ...))
and (macroexpand-1 '(do-template ...))
and got:
(do (clojure.core/seq (clojure.core/concat (clojure.core/list (symbol (str foo "-method"))) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/this)) (clojure.core/list (quote user/that)))))))) (clojure.core/seq (clojure.core/concat (clojure.core/list (symbol (str bar "-method"))) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/this)) (clojure.core/list (quote user/that)))))))) (clojure.core/seq (clojure.core/concat (clojure.core/list (symbol (str baz "-method"))) (clojure.core/list (clojure.core/apply clojure.core/vector (clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/this)) (clojure.core/list (quote user/that)))))))))
Not exactly easy to read :-).
Also, I probably want the this
and that
to be anaphora and expand to themselves: ~'this
.
(1) defprotocol is not fine with a do form. It doesn't raise an error, but it doesn't work either.
(2) You can't do what you want in this way. defprotocol is the macro being called, so it has absolute authority about how sub-forms are expanded.
(3) Item (2) suggests a solution, in fact the same one as at least one of your recent questions: define a new macro, say with-methods
, that takes a list of method names, followed by whatever other defprotocol arguments, and expands into a defprotocol with the appropriate substitutions and splicing already done, so that defprotocol can expand in peace without needing to know anything about your do-template trick.
精彩评论