如何通过defmacro生成eval defrecord

时间:2014-10-23 13:50:23

标签: clojure

这是一个非常奇怪的案例!

当我调用我的宏时,我已经达到了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就会被评估为

任何让这个宏工作的想法,或者我如何使用当前的宏输出?

here the gist with 70 lines of code

提前致谢 涓

PS:我知道这个双重``导致了这种行为,但是为了定义一个defrecord你需要所有协议和fns遵循相同的列表定义,我没有找到更好的方法来实现它

1 个答案:

答案 0 :(得分:0)

好的,我看了一下你的要点中的一些代码,至少足以理解它们正在做什么。不可否认,你的protocol-impl宏的内部工作方式让我感到困惑,特别是所有额外的后退,在我看来,通过使用这样的一般结构,你的代码可以通过重构来减少混淆: / p>

(defmacro foo [bar]
  (let [baz  (symbol (some calculation here))
        quux (map some-fn (take 2 some-collection))] 
    `(do stuff with ~baz and ~quux)))

let绑定中的实际值只是任意伪代码;这里的想法只是为了避免在宏定义中出现大量引用和取消引用,将一些计算拖入{ {1}}绑定,甚至是宏定义之外的单独函数)

但是抛开这个问题,这将解决您返回let表单而不是eval'd的问题:

defrecord

那么为什么这样做而不是这个?

(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 ... )有关,但我不明白如果整个宏定义包含在语法引用中,那怎么可能...... / p>