最近set!
、スキームインタープリターを実装するときに と クロージャーの間の競合に遭遇しました。
(set! var expr ) の説明は次のとおりです: ( tspl )
set!
varの新しいバインディングを確立するのではなく、既存のバインディングの値を変更します。最初にexprを評価し、次にvarをexprの値に代入します。変更されたバインディングのスコープ内でのvarへの後続の参照は、新しい値に評価されます。
ラムダのバインディングに関する説明は次のとおりです: ( tspl )
プロシージャが作成されると、正式なパラメータを除いて、ボディ内で自由に発生するすべての変数のバインディングがプロシージャに保持されます。その後、プロシージャが一連の実パラメータに適用されるたびに、仮パラメータが実パラメータにバインドされ、保持されたバインドが復元され、本体が評価されます。
「フリー変数」の意味がよくわかりません。私のクロージャの実装は、現在利用可能なすべての変数のスナップショットを作成し、そのスナップショットをクロージャに保存することです。クロージャが実行されるたびに、次の作業が順番に実行されます: ( code )
- 現在実行中の環境の親スコープを参照するローカル スコープ (コンテキスト) を作成します。
- スナップショット内のすべての変数を新しく作成されたスコープに保存します。
- すべての実引数を対応するパラメータの名前とともに新しいスコープに格納します。
- 新しいスコープで本体をリストとして評価します。
set!
演算子を実装する私の方法は次のとおりです: ( code )
- 指定された名前の変数を含むスコープまで、(親参照に沿って) 上方向にスコープを検索します。
- そのスコープ内の変数の値を新しいものに設定します。
この手順はほとんどの場合うまくいくように見えset!
ますが、ローカル スコープ外の外部変数を変更することを目的とする内部がある場合、set!
実際には REAL 変数を見つけることができず、クロージャーのスナップショットに保存されている変数だけを見つけることができないため、それは不可能になります。
これをコードで説明しましょう。
(define x 3)
((lambda () ;; binding(snapshot) == { x: 3 }
(set! x 4) ;; changing the value in local scope which derived from the snapshot.
(display x))) ;; ==> 4
(display x) ;; ==> 3
この競合を解決するにはどうすればよいですか?