2

多くの「特別なフォーム」は、バックグラウンドでアスタリスク バージョン (fn*、let* およびその他すべて) を使用する単なるマクロであることがわかりました。

たとえば、fn の場合、fn* だけでは提供されない分解機能がミックスに追加されます。fn* が単独でできることとできないことの詳細なドキュメントを見つけようとしましたが、それほど幸運ではありませんでした。

それは間違いなくサポートします:

  • &/キャッチオール インジケーター

    (fn* [x & rest] (do-smth-here...))
    
  • 興味深いことに、次のようにアリティのオーバーロードも行われます。

    (fn* ([x] (smth-with-one-arg ...) 
         ([x y] (smth-with-two-args ...))
    

だから私の質問は最終的に、定義するだけではないのはなぜですか:

(fn& [& all-args] ...)

これは絶対に最小限であり、マクロを介してすべてのアリティ選択を提供できます (パラメーター リストのサイズのチェック、コード パスを指示する if/case ステートメント、最初のいくつかのパラメーターを目的のシンボルにバインドするなど)。

これはパフォーマンス上の理由によるものですか? おそらく誰かが、便利なアスタリスク特殊フォームの実際の標準定義へのリンクを持っているかもしれません。

4

3 に答える 3

5

アリティの選択は、JVM 仮想メソッド ディスパッチを利用します。各アリティ (0 から 20 個の引数) には独自のメソッドがあり、21 個以上のアリティには単一のメソッドがあります。

applyToで提案するものに似たジェネリックメソッドであるメソッドに気付くかもしれませんfn&。その実装は、正しい特殊なメソッドを選択するための単なる巨大なスイッチです。

于 2015-09-15T22:36:58.217 に答える
3

はい、提案する超プリミティブの上にマクロとしてすべてを実行できますfn&。これにより、コンパイラの実装が確実に簡素化されます。これが行われない理由は、一部はパフォーマンス上の理由 (かなり遅く、JVM にはすでにアリティに基づいてディスパッチするための高速な機能があります) であり、一部は「表面的」です: 関数の各アリティが異なることを意味します。関数がコンパイルされる JVM クラスのメソッド。これにより、スタック トレースがより適切になります。これは、JIT が関数をよりよく「理解」するのにも役立ち、それに応じて最適化できます。

于 2015-09-15T22:32:13.067 に答える
0

私の推測では、これは利便性/拡張性に基づいていると思います。コンパイラ (fn* は実際には「定義」/処理されている) は Java で記述されており、言語をブートストラップするために最低限必要な機能を処理しますが、fn はその上に構築されるマクロです。他のいくつかのフォームと同じです。コンパイラを Java から clojure に書き直すことはできるが、その利点は見られないという Rich の発言がどこかにありました (間違っていたら訂正してください)。

于 2015-09-15T22:29:05.730 に答える