Clojure 如何评估defmacro生成的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

这真是个奇怪的案子

当我调用宏时,我已经达到了defrecord定义,但是我只得到了没有计算的代码

(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列表中使用“~”引起的,例如~()或~@()。因此,如果您使用双引号``语法,则需要双引号~~来拆分参数值。但是在上面的示例中,如果删除第二个反勾号(在匿名函数中,在宏定义的一半),这样宏定义的开头只有一个反勾号,出于某种原因,您仍然会得到相同的错误。