Clojure 如何评估defmacro生成的defrecord
这真是个奇怪的案子 当我调用宏时,我已经达到了defrecord定义,但是我只得到了没有计算的代码Clojure 如何评估defmacro生成的defrecord,clojure,Clojure,这真是个奇怪的案子 当我调用宏时,我已经达到了defrecord定义,但是我只得到了没有计算的代码 (defmacro protocol-impl [protocol-definition] ``(defrecord ~(symbol "my-wrapper") [~(symbol "e#")] ~@(let [[type# protocol-functions#] ~protocol-definition] (conj (map
(defmacro protocol-impl [protocol-definition]
``(defrecord ~(symbol "my-wrapper") [~(symbol "e#")]
~@(let [[type# protocol-functions#] ~protocol-definition]
(conj
(map
(fn [[function-name# function-args#]]
`(~function-name# ~function-args#
(~function-name# ~(symbol "e#") ~@(next function-args#))))
protocol-functions#) type#))
))
(protocol-impl (adapt-super-impls (first (get-methods (Example.)))))
;;=> (clojure.core/defrecord
;; my-wrapper
;; [e#]
;; wrapper.core.Welcome
;; (say_bye [this# a# b#] (say_bye e# a# b#))
;; (greetings [this#] (greetings e#)))
如果我尝试
(my-wrapper. (Example.))
=> Unable to resolve classname: my-wrapper
但是,如果我在nrepl中评估宏调用生成的输出,则defrecord的评估结果很好
有没有办法让这个宏正常工作,或者如何处理当前的宏输出
提前谢谢
胡安
PS:我知道这种双重“导致了这种行为,但要定义一个defrecord,您需要所有协议和FN都遵循相同的列表定义,我没有找到更好的方法来实现它好的,我查看了您要点中的一些代码,至少足以理解它在做什么。诚然,
protocol impl
宏的内部工作方式让我感到困惑,尤其是所有额外的背景标记,在我看来,通过使用如下一般结构,您的代码可以被重构,以减少混乱:
(defmacro foo [bar]
(let [baz (symbol (some calculation here))
quux (map some-fn (take 2 some-collection))]
`(do stuff with ~baz and ~quux)))
(在let
绑定中的实际值只是任意的伪代码;这里的想法只是为了避免在宏定义中出现大量的引用和取消引用,方法是将一些计算拖出到let
绑定中,甚至拖出到宏定义之外的单独函数中)
但抛开这个问题不谈,这将解决返回defrecord
表单而不是eval'd的问题:
(defmacro protocol-impl [protocol-definition]
`(eval
`(defrecord ... etc.
(protocol-impl '[wrapper.core.Welcome
([say_bye [this a b]]
[greetings [this]])])
(my-wrapper. (Example.))
;=> #wrapper.core.my-wrapper{:e# #wrapper.core.Example{}}
那么,为什么这样做有效而不是这样呢
(defmacro protocol-impl [protocol-definition]
`(defrecord ... etc.
(protocol-impl '[wrapper.core.Welcome
([say_bye [this a b]]
[greetings [this]])])
;=> Exception in thread "main" java.lang.IllegalStateException:
;=> Attempting to call unbound fn: #'clojure.core/unquote ...
我完全不知道。假设它与在语法引号形式之外使用unquote(
~
)有关,但我不明白如果整个宏定义都用语法引号括起来怎么可能…我不明白为什么需要双引号“`…”。。。如果只执行一个`?@DaveYarwood,会发生什么情况?这里的问题是进入(defrecord…)同一列表中的所有参数,而不是嵌套列表。我找不到更好的方法来实现它:)谢谢你在这方面花时间,当你得到;=>试图调用unbound fn:#'clojure.core/unquote是由于试图在当前的unquote列表中使用“~”引起的,例如~()或~@()。因此,如果您使用双引号``语法,则需要双引号~~来拆分参数值。但是在上面的示例中,如果删除第二个反勾号(在匿名函数中,在宏定义的一半),这样宏定义的开头只有一个反勾号,出于某种原因,您仍然会得到相同的错误。