3

別の名前空間から呼び出そうとしているマクロ生成マクロがあり、「存在しない修飾変数を参照できません」で失敗します。

問題を例示する最も単純な次のコードでそれを再現することができました。回避策も見つけましたが、問題の原因と、より良い解決策が存在するかどうかを理解したいと思います。

問題

ファイルfoo.clj

(ns foo)
(defmacro create-my-macro []
  `(defmacro my-macro []
      nil))

ファイルboo.clj

(ns boo (:use [foo]))
(create-my-macro)

上記のコードを次のコマンドで実行した場合:

java -cp clojure-1.4.0.jar clojure.main boo.clj

...で失敗します:

Exception in thread "main" java.lang.RuntimeException: Can't refer to qualified var that doesn't exist, compiling:(...boo.clj:2)

回避策

何らかの理由で、作成するマクロの名前をパラメーターとして受け入れるようにマクロ生成マクロを拡張しても、失敗はありません。

ファイルfoo.clj

(ns foo)
(defmacro create-my-macro [macroName]
  (let [the-macroName (symbol macroName)]
    `(defmacro ~the-macroName []
         1)))

ファイルboo.clj

(ns boo (:use [foo]))
(create-my-macro "foo")
(println (foo))

上記のようにファイルboo.cljを実行すると、文句なしにコンソールにクリーンな「1」が出力されます。

では、最初のケースで何が問題だったのでしょうか。また、マクロを生成するマクロの名前をパラメーターとして受け入れるように変更して、それを修正する別の方法はありますか?また、macro-generated-macroが同じ名前空間から呼び出されたときに失敗しないのはなぜですか?

4

2 に答える 2

4

マクロで、シンボルが記述されている名前空間ではなく、実行されている名前空間にシンボルを導入する場合は、 と get defmacro の組み合わせを使用してunquotequoteマクロ展開時にプレーンな非修飾シンボルを生成できます。

(ns foo)
(defmacro create-my-macro []
  `(defmacro ~'my-macro []
      nil))

boo> (my-macro) 
nil

の呼び出し(symbol macroName)は、文字列から名前空間修飾されていないシンボルを作成することで、ほとんど同じことを実現します。最初の例で同じフォームを使用できます。

(defmacro create-my-macro []
  `(defmacro ~(symbol "my-macro") [] 
      "new-result")) 

boo> (my-macro) 
"new-result"
于 2013-02-27T19:19:06.803 に答える
1

「それで、最初のケースで何が間違っていたのでしょうか。マクロ生成マクロを変更して、生成されるマクロの名前をパラメーターとして受け入れるように変更する別の方法はありますか?」

間違っているのは、マクロが「シンボル キャプチャ」と呼ばれるものを実行しようとしていることです。マクロは、ターゲット名前空間の既存のシンボルを上書きする可能性のあるシンボルを定義しようとしており、clojure は関連するバグからユーザーを保護しようとしています。シンボルキャプチャ付き。

必要なのはシンボルのキャプチャであると確信している場合は、上記の Arthur Ulfeldt が提案していることを実行する必要があります (unquote と引用符の組み合わせ ~'my-macro を使用)

ただし、最初のソリューションのバリエーションを使用して、マクロが現在の名前空間で変数を定義するという事実を明示することをお勧めします。

(ns foo)
(defmacro create-my-macro [macroName]
  `(defmacro ~macroName [] `1))

マクロの呼び出しは次のようになります。

(create-my-macro mymacro)

これにより、「mymacro」というマクロが作成され、次のように呼び出すことができます。

(mymacro)   ;; would return 1

「また、マクロ生成マクロが同じ名前空間から呼び出されたときに失敗しないのはなぜですか?」

これについてはわかりませんが、マクロが存在する同じ名前空間でシンボルを定義しているため、既に使用されているシンボルを知っていると想定され、意図せずに既に使用されているシンボルを上書き (キャプチャ) しない責任があると推測されます. 一方、別の名前空間からの呼び出しの場合、シンボル キャプチャ (許可されている場合) は、驚くべき副作用をもたらします。繰り返しますが、これは私の推測です。

于 2013-02-27T21:23:44.913 に答える