確かに:その部分式のfree variablesを計算し、何とかASTにそれを添付して、すべての部分式のために。そして、再帰的呼び出しであるeval
を呼び出すたびに、評価しようとしている式の空き変数だけに環境を制限します。
コンパイラは通常、これらの参照を保持するとオブジェクトがGCされない可能性があるため、不要な値への参照を保持するクロージャの作成を避けるために、lambda
の境界でこれを行います。それは次のプログラム
(let ([x 1]
[y 2])
(lambda (z) ;; free vars = {x}
(+ x z))
x
の値が含まれますlambda
発現させるための閉鎖ではなくy
のために、です。しかし、一般的には、これは単純ではない「フレームのリスト」環境表現を使用できないことを意味します。それを平らにしなければならないかもしれません(または少なくともコピーして剪定してください)。
一部の実装では、ローカル変数(クロージャによって保持されていない変数、レジスタやスタックで見られると思われる変数)が使用されなくなったとき、特にテール以外の呼び出しの前にはゼロになります。これは、
(let ([x some-big-object])
(f (g x) long-running-expression-not-involving-x))
が
(let ([x some-big-object])
(let ([tmp1 (g x)])
(set! x #f)
(let ([tmp2 long-running-expression-not-involving-x])
(f tmp1 tmp2))))
の低レベルと同等に翻訳される可能性がありますされる理由は同じです:可能な限り早期の参照をドロップすると、オブジェクトが潜在的に早く解放されることを意味します。 (閉鎖の場合と同様に、キャプチャされた継続によって保持されないことも意味します。)Googleの詳細については、「スペースの安全」を参照してください。
中間表現はいかに強く依存すると思いますか? – Aslan986
私は、字句環境のSICPエバリュエーターから始めるとします。 – Andreas
"効率的なインタープリタ"は擬似語です。効率的にしたいのであれば、コンパイラを書くだけです。 「私が300ポンド以下に落ちないという制約を条件に、私ができる最も効率的な長距離ランナーになるにはどうすればいい? – Kaz