Files
hakorune/docs/development/current/main/design/loop-canonicalizer.md

3.9 KiB
Raw Blame History

Loop Canonicalizer設計 SSOT

Status: Design (P0)
Scope: ループ形の組み合わせ爆発を抑えるための “前処理” の設計fixture/shape guard/fail-fast と整合)
Related:

  • SSOT (契約/不変条件): docs/development/current/main/joinir-architecture-overview.md
  • SSOT (地図/入口): docs/development/current/main/design/joinir-design-map.md
  • SSOT (パターン空間): docs/development/current/main/loop_pattern_space.md

目的

  • 実アプリ由来のループ形を、fixture + shape guard + Fail-Fast の段階投入で飲み込む方針を維持したまま、
    “パターン数を増やさない” 形でスケールさせる。
  • ループ lowerer が「検出 + 正規化 + merge 契約」を同時に背負って肥大化するのを防ぎ、責務を前処理に寄せる。

推奨配置(結論)

おすすめ: AST → LoopSkeleton → JoinIR(Structured) の前処理として Canonicalizer を置く。

  • 「組み合わせ爆発」が Pattern 検出/shape guard の手前で起きるため、Normalized 変換だけでは吸収しきれない。
  • LoopSkeleton を SSOT にすると、lowerer は “骨格を吐く” だけの薄い箱になり、Fail-Fast の理由が明確になる。

代替案(参考):

  • Structured JoinIR → Normalized JoinIR を実質 Canonicalizer とみなす(既存延長)。
    ただし「検出/整理の肥大」は Structured 生成側に残りやすい。

LoopSkeletonSSOT になる出力)

Canonicalizer の出力は “ループの骨格” に限る。例示フィールド:

  • steps: Vec<Step>
    • HeaderCond(あれば)
    • BodyInitbody-local 初期化を分離するなら)
    • BreakCheck / ContinueCheck(あれば)
    • Updatescarrier 更新規則)
    • Tail(継続呼び出し/次ステップ)
  • carriers: Vec<CarrierSlot>loop var を含む。役割/更新規則/境界通過の契約)
  • exits: ExitContractbreak/continue/return の有無と payload
  • captured: Vec<CapturedSlot>(外側変数の取り込み)
  • derived: Vec<DerivedSlot>digit_pos 等の派生値)

Capability Guardshape guard の上位化)

Skeleton を生成できても、lower/merge 契約が成立するとは限らない。
そこで SkeletonGuard を “Capability の集合” として設計する。

例:

  • RequiresConstStepIncrementi=i+const のみ)
  • BreakOnlyOnce / ContinueOnlyInTail
  • NoSideEffectInHeaderheader に副作用がない)
  • ExitBindingsComplete(境界へ渡す値が過不足ない)

未達の場合は Fail-Fast理由を RoutingDecision に載せる)。

RoutingDecision理由の SSOT

Canonicalizer は “できない理由” を機械的に返す。

  • RoutingDecision { chosen, missing_caps, notes, error_tags }
  • missing_caps は定型の語彙で出す(ログ/デバッグ/統計で集約可能にする)

Corpus / Signature拡張のための仕組み

将来の規模増加に備え、ループ形の差分検知を Skeleton ベースで行えるようにする。

  • LoopSkeletonSignature = hash(steps + exit_contract + carrier_roles + required_caps)
  • 既知集合との差分が出たら “fixture 化候補” として扱う(設計上の導線)。

実装の境界(非目標)

  • 新しい言語仕様/ルール実装はしない(既存の意味論を保つ)。
  • 非 JoinIR への退避prohibited fallbackは導入しない。
  • 既定挙動は変えない(必要なら dev-only で段階投入する)。

追加・変更チェックリスト

  • 追加するループ形を最小 fixture に落とす(再現固定)
  • LoopSkeleton の差分steps/exits/carriersを明示する
  • 必要 Capability を列挙し、未達は Fail-Fast理由が出る
  • 既存 smoke/verify が退行しないquick は重くしない)