どうしたの
これは、現在の名前空間の概念が Clojure でどのように機能するかによって発生します。macroexpand-1現在の名前空間で引数を展開します。
REPL では、これはuser; 名前空間でマクロを定義しているuser場合、その名前空間で呼び出すmacroexpand-1と、すべて問題ありません。
名前空間、:gen-class'dまたは実際には他の名前空間では、コンパイル時の現在の名前空間はその名前空間そのものです。ただし、後でこの名前空間で定義されたコードを呼び出すと、その時点で適切な名前空間が現在の名前空間になります。コンパイルされると、それは他の名前空間になる可能性があります。
最後に、アプリの実行時のデフォルトの現在の名前空間はuserです。
これを確認するには、マクロを別の名前空間に移動して、関数も定義し、use-the-macroこの関数を最上位で呼び出します。'd 名前空間は、:gen-classマクロの名前空間を要求または使用する必要があります。次にlein run、(マクロの名前空間のコンパイル時に) 期待するものを 1 回出力し、展開されていない形式を 2 回 (マクロの名前空間がrequireメインの名前空間によって d され、次に が-main呼び出されたときにuse-the-macro) 出力します。
ソリューション
Clojure REPL はbinding;を使用して現在の名前空間を制御します。同じことができます:
(binding [*ns* (the-ns 'scratchpad.core)]
(prn (macroexpand-1 ...)))
quote in の代わりに syntax-quote を使用することもできます-main。
(defn -main [& args]
(prn (macroexpand-1 `...)))
^- changed this
もちろん、以外のシンボルunlessが関係している場合は、それらを出力で名前空間修飾する必要があるかどうかを決定し、場合によってはプレフィックスを付ける必要があります~'。ただし、これがポイントです。syntax-quote は、ほとんど「名前空間に依存しない」コードを生成するのに適しています (これが、便利な構文に加えて、マクロを作成するのに非常に優れている理由です)。
別の可能な「修正」(Clojure 1.5.1でテスト済み)は、へのin-ns呼び出しを追加すること-mainです:
(defn -main [& args]
(in-ns 'scratchpad.core)
(prn (macroexpand-1 '...)))
^- no change here this time
と同様にbinding、このようにして、元の名前空間で元のフォームの拡張を実際に取得しています。