强制扩展 Clojure 宏内的表达式
我正在尝试使用 Stuart Sierra 的 do-template
defprotocol 中的 a> 宏,并且 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-expression 被传递给 defprotocol
未展开。有没有办法让它先评估再通过?
顺便说一句, 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 ...))
并得到:
(做(clojure.core/seq (clojure.core/concat (clojure.core/list(符号(str foo “-方法”)))(clojure.core/list (clojure.core/应用 clojure.core/向量(clojure.core/seq (clojure.core/concat (clojure.core/list(引用用户/this)) (clojure.core/list(引用 用户/那个))))))))(clojure.core/seq (clojure.core/concat (clojure.core/list(符号(str 条 “-方法”)))(clojure.core/list (clojure.core/应用 clojure.core/向量(clojure.core/seq (clojure.core/concat (clojure.core/list(引用用户/this)) (clojure.core/list(引用 用户/那个))))))))(clojure.core/seq (clojure.core/concat (clojure.core/list(符号(str baz “-方法”)))(clojure.core/list (clojure.core/应用 clojure.core/向量(clojure.core/seq (clojure.core/concat (clojure.core/list(引用用户/this)) (clojure.core/list(引用 用户/那个)))))))))
不太容易阅读:-)。
另外,我可能希望 this
和 that
成为 anaphora 并扩展为自身:~'this
。
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
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
(1) defprotocol 不适用于 do 形式。它不会引发错误,但也不起作用。
(2)这样你就不能做你想做的事了。 defprotocol 是被调用的宏,因此它对子表单如何展开有绝对的权威。
(3) 第 (2) 项提出了一种解决方案,实际上与您最近的至少一个问题相同:定义一个新宏,例如
with-methods
,它采用方法名称列表,后面跟着任何其他 defprotocol 参数,并扩展为一个 defprotocol,并已完成适当的替换和拼接,以便 defprotocol 可以和平地扩展,而无需了解有关 do-template 技巧的任何信息。(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.