4

質問のマクロ -> 匿名関数->を読むと、マクロが匿名関数でうまく機能しないことがわかります。マクロを正しく使用するには、実装を理解する必要があります。その意味で、マクロは「リーキー」です。実装は API によって完全に隠されているわけではありません。

(十分に複雑な) Clojure マクロがリークしやすいのは常にそうなのでしょうか?

[比較のために: 同様の問題が C プリプロセッサで発生し、マクロ引数が不注意に処理されると奇妙な副作用が見られる場合があります。その場合、マクロの引数を (マクロ内で) 括弧で囲むことによって問題を解決できます。これは可変状態 (つまり、引数を使用するたびに状態が変化する) で C マクロを使用する問題を解決しませんが、おそらく、関数型言語ではその問題を無視するか、let複数の評価を避けるために使用することができます。]

4

3 に答える 3

6

実装を理解する必要はありません。docstring は、それがどのように機能するかについて非常に明確です。リーダー マクロも十分に文書化されています - #(...) は (fn [..] ...) に展開されます。この知識と docstring が提供する情報を考えると、無名関数のスレッド化が機能しないことは明らかです。実装を理解する必要はまったくありません。

于 2012-05-25T16:15:30.387 に答える
5

その意味で、Clojureマクロはリークしません。->が#()関数で予期せず機能する理由は、#()がリーダーマクロであり、リーダーマクロが「通常の」マクロの前に展開されるためです。だからあなたは知る必要があります:

  1. マクロが行うことになっていること。->は実際には非常に基本的なマクロであり、ドキュメントではそれがどのように展開されるかをほぼ正確に説明しています。
  2. リーダーマクロを「通常の」マクロに渡したい場合に展開するもの。
于 2012-05-25T16:35:02.550 に答える
1

また、匿名関数を括弧で囲むと機能することにも注意してください。

=> (-> {:a 1 :b 2} :a (#(* 2 %)))
2

無名関数を書き出してマクロ展開すると、次のようになります。

=> (-> {:a 1 :b 2} :a ((fn [el] (* 2 el))))
2

=> (macroexpand-all '(-> {:a 1 :b 2} :a ((fn [el] (* 2 el)))))
((fn* ([el] (* 2 el))) (:a {:a 1, :b 2}))
于 2013-11-04T03:02:43.030 に答える