2011-06-19 48 views
2

我试图用一个defprotocol和Clojure的编译器里面斯图尔特Sierra的do-template宏表达式的力量扩张抱怨,我重新定义do-template - 不是我的打算:一个Clojure的内宏

(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表达式是获取传递到defprotocol未展开。有什么办法可以让它在通过之前进行评估?

BTW,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 /列表(符号(STR富 “ - 方法”))) (clojure.core /列表 (clojure.core /应用 clojure.core /载体(clojure.core/SEQ (clojure.core/CONCAT (clojure.core /列表(报价用户/本)) (Clojure的。核心/列表(引用 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(引用 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(引用 user/that)))))))))

不完全容易阅读:-)。

而且,我大概想thisthat照应和扩大自己:~'this

回答

3

(1)解决方案不适用于do表单。它不会引发错误,但它也不起作用。

(2)你不能以这种方式做你想做的事。 defprotocol是所谓的宏,所以它对子表如何扩展有绝对的权威。(3)项目(2)提出了一种解决方案,实际上至少与你最近的一个问题是一样的:定义一个新的宏,比如说with-methods,它接受一个方法名列表,然后是任何其他的解协议论证,并通过适当的替代和拼接已经完成,扩展到一个defprocolocol中,这样defprocolocol可以和平地扩展,而不需要知道任何关于do-template的技巧。

+0

谢谢。我将编写'build-protocol'和'build-reify'宏来创建适当的结构,每个结构都有一个类似'(build-protocol name simple&complex)'的签名,其中'simple'是一个“简单的“声明('(a-method [this])')和'complex'是零个或多个用'〜@'插入的形式。 – Ralph