1

それが問題なら、私はCIDERを使用しています。

(defmacro trace [prompt x]
  (let [p (subs prompt 4)
        expanded (macroexpand x)]
    (cond (seq? expanded) `(do (println ~p '~x "...")
                               (let [result ~(map #(if (or (not (symbol? %)) (function? %))
                                                     (list 'trace (join [prompt prompt]) %)
                                                     %) expanded)] 
                               (println ~p result "->" ~expanded))
                               ~expanded)
          :else expanded)))

これは私が取り組んでいるマクロですが、問題にならないはずです (問題はあるかもしれませんが)。

これは、問題を引き起こしている特定のコードです

(trace "    " (if true 6 4))

このストレートを評価すると、例外がスローされます。

Can't let qualified name: clj-match.trace/result

フォームをマクロ展開してデバッグしたところ、次のようになりました。

(do
  (println "" '(if true 6 4) "...")
  (let* [result (if true 6 4)] (println "" result "->" (if true 6 4)))
  (if true 6 4))

これはまったく悪くないので、展開されたフォームを評価してみました。驚くべきことに、それは機能し、評価は 6 でした。

なぜこれが起こるのですか?

さらに重要なことは、例外を取得するために何が間違っているのでしょうか?

4

2 に答える 2

3

let最初の 2 番目の質問:具体的には、修飾名を実際に使用しようとしているため、例外が発生していますclj-match.trace/result

これは、マクロが生成するフォーム内のローカル バインディングの名前として使用される場合(do …)に、マクロが展開される構文引用符付きフォームが原因で発生します。そのリテラルシンボルは、構文で引用された形式内で発生するため、リーダーによって名前空間修飾されます。したがって、最終結果は正しくありません (バインディングの名前は名前空間修飾されてはなりません)。を使用してこれを回避するか、明示的に構文引用符で囲まれた形式以外のシンボルを使用し、引用符を外して使用することができます。seq?resultletresult(let [clj-match.trace/result …] …)letresult#gensym

trace(ちなみに、展開が行われるコンテキストに関係なく、シンボルが実際にマクロを参照していることを確認するために、展開内のシンボルを単に引用するのではなく、構文引用符を付けたい場合があります。)

マクロを展開する実験についてはmacroexpand-1、フォームを引数として定期的に呼び出すと上記が明らかになるため、CIDERまたは別のEmacsパッケージが提供する機能を使用してインラインで展開したと思われますか? その施設がどこかバグっているのかもしれません。

于 2016-03-12T23:58:13.447 に答える
2

` リーダー マクロは、その本体内のすべてのシンボルを名前空間で修飾されるように展開します。

user=> (macroexpand `(let [a 0] a))
(let* [user/a 0] user/a)

user/aは有効なローカル バインドではありません。

解決策は、` の gensym 短縮機能を使用することです。

user=> (macroexpand `(let [a# 0] a#))
(let* [a__3__auto__ 0] a__3__auto__)

これは人間にとって読みにくいですが、実際には有効なコードを生成します。

于 2016-03-12T23:58:54.343 に答える