Clojure宏实例化异常

时间:2013-05-29 20:02:35

标签: java macros clojure javafx-2

我有一个在repl中工作的宏,它似乎在let之外的代码中工作,也在let内部工作,如下所示。然而,它也打破了,我不明白为什么。宏基本上只是将第一个arg作为要调用的函数,并将into-array放在最后一组参数之前,并将最终非集合参数的类作为参数添加到into-array中,如果它是在java类的heirarchy。

(defmacro jvar [method & args]
  (let [lastargs (last args)
        evaled-lastargs (eval lastargs)]
    (if (coll? evaled-lastargs)
      (let [firstargs (butlast args)
            klass (eval (last firstargs))
            supset (map #(supers (class %)) evaled-lastargs)
            common (apply intersection #{klass} supset)]
        (if (seq common)
          `(~method ~@(butlast firstargs) (into-array ~(first common) ~lastargs))
          `(~method ~@firstargs (into-array ~lastargs))))
      (throw (Error. "Last argument must be defn.")))))

用途: 在Repl:

jfxcircles.core>  (macroexpand '(jvar Group. Node [(Circle. 100)]))
(new Group (clojure.core/into-array javafx.scene.Node [(Circle. 100)]))
jfxcircles.core> (jvar Group. Node [(Circle. 100)])
#<Group Group@c26729e>

let

(let [root (Group.)
      scene (Scene. root 800 600) ;etc. this is for JavaFX
      ...
      circ (Circle. 100)
      inner-group1 (jvar Group. [(Circle. 100)])        ; works
      inner-group2 (jvar Group. [circ])                 ; Instantiation Exception
      inner-group3 (jvar Group. [(Rectangle. 100 100)]) ; works
      inner-group4 (jvar Group. [(Rectangle. (.getWidth scene) 100)]) ; Instantiation exception
)

所以基本上它不会在某些情况下编译,否则应该是相同的,我无法做宏扩展,因为它不会编译。有什么想法吗?

感谢

1 个答案:

答案 0 :(得分:2)

宏扩展器在编译时应用;它没有办法操纵它作为参数接收的表单的运行时值,eval或不是,除非某些表单在编译期间和运行时总是具有相同的值(自我评估表单,一些构造函数调用等)。正是由于这种幸运巧合,问题文本中提出的宏有时似乎有效;但是,如果没有将它试图通过eval获取的信息放入一组明确的参数中,那么就无法使其正常工作。