2

repl で動作するマクロがあり、次のように の外側letと内側のコードで動作するletようです。しかし、それも壊れており、その理由はわかりません。マクロは基本的に、呼び出す関数として最初の引数を取り、into-array引数の最後のセットの前に配置し、最後の非コレクション引数のクラスをパラメーターとして配列に追加します (Java クラスにある場合)。階層。

(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
)

したがって、基本的には、そうでなければ同じであるはずの特定の状況下ではコンパイルされません。コンパイルされないため、マクロ展開を行うことができません。何か案は?

ありがとう

4

1 に答える 1

2

マクロ エキスパンダーはコンパイル時に適用されます。引数として受け取ったフォームの実行時の値を操作する方法はありevalません。ただし、一部のフォームはコンパイル時および実行時に常に同じ値を持つという意味を除きます (自己評価フォーム、一部のコンストラクター呼び出しなど)。 )。質問テキストに示されているマクロが機能しているように見えるのは、この種の幸運な偶然によるものです。evalただし、取得しようとする情報を明示的な引数のセットにすることなく、一般的に機能させる方法はありません。

于 2013-05-29T21:28:40.863 に答える