5

これは、 Clojure マクロを関数として扱うで説明した問題に似ていますが、一番上の回答のアプローチを試みると、エラーが発生しました。私の特定のアプリケーションは非常に複雑なので、あまり多くの情報が必要ないことを願っていますが、ここに私がやろうとしたことの要約版があります:

(defmacro make-fn [m arg1] 
    `(fn [& args#] 
      (eval `(~'~m ~'~arg1 ~@args#))))

このコンテキストでマクロを使用しました:

(let [columns (make-columns table-width)
       table-name (keyword (str "table_" n))]
  (apply (make-fn helpers/tbl table-name) columns))

「helpers/tbl」は、テーブル名のキーワードと、列の指定を含む可変数のリスト ([:varchar 100] など) を期待するマクロです。いくつかのテストを容易にするために、その場でランダムなデータベース テーブル仕様を作成しようとしています。とにかく、上記のコードを実行しようとすると、次のエラーが発生します。

CompilerException java.lang.RuntimeException: Unable to resolve symbol: table-name in this context, compiling:(NO_SOURCE_PATH:1) 

私は問題をある程度把握しています.マクロ展開はコンパイル時に行われ、マクロ展開にランタイム値を含めようとしているため、すべてを正しく設定するために引用符と引用符を外すという奇妙な使用があります. 私は基本的にマクロのパーシャルが必要であり、このメカニズムをさまざまな名前空間のさまざまなマクロに再利用できるようにする必要があり、すべての変数解決が正しく行われるようにする必要があります。これは可能ですか?

4

1 に答える 1

2

この問題は、Clojureがsyntax-quote(バックティック)式内のシンボルを解決する方法が原因で発生します。意図しない変数のキャプチャを回避するために、Clojureは常に、構文引用式内のシンボルを(ローカルではなく)Varを参照しているものとして解釈します。

これを回避するには、syntax-quoteによって生成されたものと同等の「独自の」フォーム構築コードを作成します。それは罪と同じくらい醜いです、しかしそれは働きます...ただ私があなたに警告しなかったと言わないでください:

(defmacro make-fn [m arg1]
  (let [g (gensym)]
    (list 'fn ['& g]
      (list 'eval (list 'concat (list 'list m arg1) g)))))

うわー、これは私のCommonLisp時代へのフラッシュバックのようなものです...

于 2012-09-25T21:52:22.990 に答える