强制在Clojure宏中扩展表达式 [英] Force expansion of an expression inside a Clojure macro

查看:126
本文介绍了强制在Clojure宏中扩展表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Stuart Sierra的 do-template defprotocol 中的 宏和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 未展开。在传递之前是否有任何方式进行评估?



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆