日本語 · English(未訳)

ADR-53: 束縛右辺の名前解決境界とメモ化の正しさ——ラムダ変数捕獲の遮断・tz 名検査の順序独立

判断: 束縛(本体層 top-level・premise 公開語・糖衣段)の右辺の名前解決は 「束縛・premise 語・前文メンバー・列挙」で閉じる——呼び出し側のラムダ変数には落とさず、 誘導つき静的エラーにする(点に依存する値は引数付き束縛 T(x) = … で明示・使用は T(d))。 あわせて、メモ化キャッシュのヒット時に記録済みの tz 名検査(ADR-40)を現在の predicateAlign で 再実行する——検査の順序独立性と、解決値のクロージャ同一性(labelStack ガードの前提)を両立させる。

(発端=還流第 16 便・収蔵 17: 供給側がメモ化〈5e2b545〉への追随の敵対的レビューで検出した バグ 2 件——①右辺が呼び出し側ローカルを掴む束縛で、最初に評価された点(通例は実体化原点 epoch)の値が全点に焼き付き、エラーも警告も無く点集合が変わる ②ADR-40 の tz 名検査が 文の並び順・単一文内の整列切替で有効/無効が変わる。全 9 再現形を当方 impl で確認・ 2026-08-26 設計者裁定=静的エラー化・1.0 前処置)。

  1. 仕様の隙間の閉じ方: spec §4.8「premise は焼き込まず遅延解決」の遅延解決の対象は premise(前文メンバー・公開語——wkst・weekday 級)であり、呼び出し側の値束縛 (ラムダ変数)は含まない——これを明文化する。従来実装は名前解決が locals 鎖へ素通しで 落ちるため T = ordinalIn(day, month, d)d が使用箇所の filter(d => …) に偶然 解決されていた(規定外の挙動)。この形を合法(マクロ捕獲)と認めると、定義の意味が使用 箇所の変数名に依存するfilter(x => …) の中では未解決)——「定義がテキストのまま境界を 渡る・定義単体で読める」という言語の根本思想への正面の反であり、衛生(hygiene)問題を仕様に 持ち込む。ゆえに遮断が筋。
  2. 互換影響ゼロの実測: 既存コーパス(当方 607 テスト・doctest 全数・供給側 976 unit・ 配信 11 定義・運用ソース全体)にこの形は無い(第 16 便 §3 の実測——だからこそ両者の既存 テストを素通りしてレビューまで残った)。誘導先(引数付き束縛)は現行で正答することを実測 済み。完全未知名 T = foo + 1 は従来から「未解決の名前」——本判断はそれと同じ面へ 「locals にだけ解決できる名前」を倒す整合的な拡張。
  3. 遮断の実装: 右辺評価の env から locals 鎖を切る(locals: null, parent: null——parent 鎖の用途は locals 解決のみ)。誘導のため遮断前の env を保持し(severedLocalsEnv・ネスト 束縛では最外の遮断点を保持——間接参照 B = T + 0 経由でも「呼び出し側のラムダ変数」を 名指しできる)、「未解決の名前」より先に専用診断を出す。推移形(間接参照・premise 公開語 経由)も遮断が根で断つ——第 16 便 §1 の「是正設計への注意」(直接形だけ塞いでも閉じない・ 依存閉包の設計判断が要る)は、捕獲そのものを非合法化することで依存解析なしに解消する。 引数付き束縛の閉包 env・糖衣段(applyStage)の右辺評価も同一原則(実引数は遮断前の呼び出し側 env で評価——値渡しの意味は不変)。
  4. メモ化は正となる: 束縛右辺が呼び出し側 locals に依存し得なくなるため、premise 名+前文 メンバー 8 成分の文脈キーで値の共有は正しい(第 16 便 §1 の焼き付きは構造的に不可能に なる)。O(N²) 封止(メモ化の本旨・2026-08-03)はそのまま。
  5. tz 名検査の順序独立(§2 の閉じ方): 検査(ADR-40)は値でなく評価器状態 (predicateAlign)に依るため、キャッシュヒットで右辺評価ごと飛ぶと「最初に評価された 文脈の検査 1 回で以降の文脈が素通る」(並び順・単一文内の整列切替のいずれでも・premise 公開語経路にも同型——第 16 便 §2 の全再現形)。閉じ方は検査をキャッシュの外へ出す (第 16 便 §2 の代替案): 右辺評価中に踏んだ predicateAlign 文脈の検査を(win grain・診断名で 重複排除して)キャッシュエントリへ記録し、ヒット時にも現在の predicateAlign で再実行する。 対象は defCache の全 3 経路(本体層束縛・premise 公開語・カレンダー実体の bizDay 標準導出)。
  6. キーに align を足す案・メモ化スキップ案は不採——ともに当方で実測して棄却した。align を キーに足すと、label: 付与式の評価(windowInstance が predicateAlign を設定する)と外側評価とで キーが割れて再評価が走り、解決値のクロージャ同一性が失われて labelStack ガード (ADR-34/42 判断 7 (f))が糖衣循環の別文言に化ける(当方 instance-reference (f) の回帰で 実測——第 16 便が予告した「シャドウ形で保存されない」と同族の、整列切替形での破れ)。 供給側先行是正の「真の自由名によるメモ化スキップ」も判断 1 の裁定(静的エラー化)の下では 不要になり、スキップ判定の罠 2 種(診断の変化・名前衝突での O(N²) 復帰=第 16 便 §1 の 共有知見)ごと回避される。検査の記録・再実行は値の同一性を保ったまま検査だけ毎文脈で 立てる——両立の唯一解に近い。
  7. 性能: 記録は重複排除つき(ユニークな検査は式中の射影箇所数程度)・再実行は tz 名比較 数回で、617 テストの所要は従来と同水準(重複排除なしの素朴な記録は点ごとに積まれ、ヒット時 再実行が O(N²) を戻すことを実測——同じ轍を踏まないための註記)。

経緯: 供給側がメモ化追随の敵対的レビューでバグ 2 件を検出(写経は成功・「写経した意味そのものが 退行を生む」型=還流第 16 便・1.0 宣言の判断材料として番号繰り上げの先行提供)→当方全 9 形 再現→設計者裁定(①静的エラー化 ②1.0 前処置・2026-08-26)→実装(遮断+記録・再実行・ テスト 10 本〈誘導 3 面・正道 3 形・順序 3 形・偽陽性なし 1〉)。供給側の先行是正 2 点 (メモ化スキップ・align 鍵)は本 ADR の公開をもって当方形へ追随・解消される見込み(第 16 便 §3 の申し合わせ)。