14

letバインディングを実装する方法は 2 つあります。まず、SICPから知られているように、ラムダ関数letとして実装できます。これは便利で簡単ですが、JVM では各ラムダ ( ) が個別のクラスに変換され、平均的なプログラムで何度も使用されるという事実を考慮すると、これは非常に高価に思えます。fnlet

次に、バインディングをローカル Java 変数letに直接変換できます。これによりオーバーヘッドはほとんど発生しませんが、バインディングをスタックに格納すると言語のセマンティクスが壊れます。この場合、クロージャーの作成は不可能です。保存された値は、スタックの巻き戻しの直後に破棄されます。

では、Clojure で実際に使用されている実装は何ですか? Clojure ソース内の対応する行を参照していただければ幸いです。

4

2 に答える 2

17

letバインドされた変数は、最終的なローカル値としてスタックに格納されます。

それらは final であるため、必要に応じてクロージャーにバインドできます (これは、Java の匿名内部クラスで final ローカル変数を使用する方法に似ています)。内部的には、JVM はクロージャを表すオブジェクトに値をコピーします (最終フィールドとして格納されます)。その結果、スタック フレームがなくなった後でも、クロージャーは機能します。

全体として、let バインド変数はオーバーヘッドが非常に低いため、パフォーマンスの観点から使用することをためらう必要はありません。JVM でこれ以上のことを行うことはおそらく不可能です。

于 2012-05-16T03:02:12.230 に答える
1

ローカル変数は、スタック上に割り当てられ、ヒープ上の値/オブジェクトを指すポインターです。ポインターはスコープ外になりますが、クロージャーがオブジェクトへのポインターを保持している限り、オブジェクトは存続します。

于 2012-05-16T19:22:32.307 に答える