强制在Clojure宏中扩展表达式 [英] Force expansion of an expression inside a Clojure macro
问题描述
我想使用Stuart Sierra的 do-template
宏和Clojure编译器抱怨我正在重新定义 defprotocol
中的 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-expression正在传递到 defprotocol
未展开。在传递之前是否有任何方式进行评估?
BTW, do-template
(do
(foo-method [this that])
])
(baz-method [this that]))
(带有手动展开的版本), 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 / apply
clojure.core / vector (clojure.core / seq
(clojure.core / concat
(clojure.core / list(quote user / this))
(clojure.core / list / that))))))))(clojure.core / seq
(clojure.core / concat
(clojure.core / list(str bar
-method) ))(clojure.core / list
(clojure.core / apply
clojure.core / vector(clojure.core / seq
(clojure.core / concat
)核心/列表(quote user / this))
(clojure.core / list(quote
user / that))))))))(clojure.core / seq
core / concat
(clojure.core / list(strbaz
-method)))(clojure.core / list
(clojure.core / apply
clojure .core / seq
(clojure.core / concat
(clojure.core / list(quote user / this))
(clojure.core / list b $ b user / that))))))))))
不太容易阅读: >
另外,我可能希望 this
和的
em> anaphora 并展开给自己:〜'this
。
(1)defprotocol不好用do表单。它不会引发错误,但它也不工作。
(2)你不能这样做你想要的。 defprotocol是被调用的宏,因此它具有关于子表单如何扩展的绝对权威。
(3)项目(2)建议一个解决方案,一个作为您最近的问题之一:定义一个新的宏,用<-c $ c> with-methods 命令,它接受一个方法名称列表,后跟任何其他的defprotocol参数,然后展开成为一个defprotocol与适当的替代和拼接已经完成,以便defprotocol可以扩大在没有必要知道你的do-template伎俩的任何和平。
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])
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.
这篇关于强制在Clojure宏中扩展表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!