开发者

Force expansion of an expression inside a Clojure macro

开发者 https://www.devze.com 2023-03-14 03:22 出处:网络
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:

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消