CLtL2 では、スコープとエクステントの区別が明確になりました。レキシカル変数と特殊変数に関して、私の考えでは、レキシカル変数は「レキシカル スコープが無期限である」のに対して、特殊変数は「動的拡張で無期限にスコープが設定されている」というものです。</p>
私の質問は、「レキシカルおよび特殊変数」のセマンティクスは、一般的に内部でどのように実装されているのでしょうか? 「一般的に」とは、一般的な考えで十分だという意味です。Lisp の長い歴史を考えると、これらの基本的な概念を実装するために適用された多くの最適化があるはずです。
議論を開始するために、私は以下の推測を試みます。
すべては環境から始まります。環境はフレームのシーケンスであり、各フレームは名前を場所にマップするテーブルです (その値は取得および保存できます)。そのような各マッピングは、場所への名前のバインディングです。フレームは囲み関係によってリンクされます。内側のフレームの名前は、外側のフレームの同じ名前を隠すことができます。declare
また、 -d/ declaim
-ed/ proclaim
-ed が特別でない限り、Common Lisp のバインディングはデフォルトでレキシカルです。
セマンティクスには、名前の検索と新しいバインディングの作成という 2 つの側面があります。
新しいバインディングを作成します。
lambda
式、let
/let*
、labels
/flet
、macrolet
、およびそれらを使用するマクロはバインディングを作成します。レキシカル バインディングは、新しいフレームを作成し、現在のレキシカル環境を新しく作成されたフレームのエンクロージング環境にすることによって作成されます。特別なバインディング (明示的に宣言する必要があります) は、現在のパッケージ内の名前に対して作成されたスタックの一番上に新しい場所をプッシュします (スタックはおそらく名前のハッシュ テーブルによって見つけることができます) — スタックは実装に使用されます。構築フォームが終了したときに、スタックをポップすることでバインディングを分解できるように、動的エクステントを設定します (問題は、おそらくunwind-protect
ボンネットの下のようなものを使用して、そうする方法を確認することです)。名前検索。特別であると明示的に宣言されていない限り、名前のルックアップは、バインディングの作成中に確立されたフレーム リンクを介して、レキシカル環境でのルックアップにデフォルト設定されます。検索プロセスで最初に一致した名前が勝ちます。特別な名前 (明示的に宣言する必要があります) の場合、ルックアップはスタックの一番上を調べることによって提供されます。