|
14 | 14 | -- |
15 | 15 | -- Layers (mirroring the Coq twin): |
16 | 16 | -- 4a append-context algebra (tappend/uappend + injectivity/split) [VERIFIED] |
17 | | --- 4b shape + shift (shapeType [VERIFIED]; hvShift/htShift/ |
| 17 | +-- 4b shape + shift (shapeType/hvShift/htShift [VERIFIED]; |
18 | 18 | -- htShift0/weakeningAppend — PENDING) |
19 | 19 | -- 4c substitution core (reassoc algebra, hvSubst, htSubst, |
20 | 20 | -- substLemma0, subst2Lemma — PENDING) |
21 | 21 | -- 4d preservation (consumes 4c; congruences recurse on Step |
22 | 22 | -- — PENDING; Soundness.preservation stays |
23 | 23 | -- the honest hole until 4d lands) |
24 | 24 | -- |
25 | | --- STATUS (Idris track, #108): this module is HOLE-FREE for the layers it |
26 | | --- currently contains (4a + the shape invariant). It does NOT yet prove |
27 | | --- preservation. The remaining layers each thread the type context (and term) |
28 | | --- RELEVANTLY because Idris erases the indices of `Has`/`HasVar` (ADR-003) — |
29 | | --- the same wall the `progress` proof navigated with explicit-term recursion. |
30 | | --- That makes the Idris port heavier than the Coq original (whose `Prop` |
31 | | --- indices erase without blocking the proofs), but the technique is settled |
32 | | --- (see `shapeType`/`shapeVar` below): pass `g`/`t` explicitly, recurse on the |
33 | | --- non-binding premise so erased branch-binder types are never demanded. |
| 25 | +-- STATUS (Idris track, #108): HOLE-FREE for the layers it currently contains — |
| 26 | +-- 4a (append algebra), the shape invariant, `hvShift` (has_var weakening), |
| 27 | +-- the structural shift index `shiftIdx`/`shiftIdxCorrect`/`shiftVarLemma`, and |
| 28 | +-- `htShift` (term weakening, all 14 constructor cases, total) on top of its |
| 29 | +-- support lemmas (`unitInv`, `usplitLemma`, `uaddUshift`, `ushiftUscale`). |
| 30 | +-- It does NOT yet prove preservation (htSubst/subst2Lemma/preservation pending). |
| 31 | +-- |
| 32 | +-- ARCHITECTURAL BLOCKER on `htShift` — RESOLVED 2026-06-15 via Option A. |
| 33 | +-- `htShift` shifts under binders, so its binder cases extend the type context |
| 34 | +-- with the binder's type and recurse on the BODY. For `Lam q a body` the bound |
| 35 | +-- type `a` is in the term and recoverable. But `Let`/`Case`/`LetPair` did NOT |
| 36 | +-- annotate their bound types in the term — those types lived only as ERASED |
| 37 | +-- indices of the typing derivation (`THLet`/`THCase`/`THLetPair`), so the |
| 38 | +-- extended context `TSnoc i <bound-type>` for the body recursion could not be |
| 39 | +-- constructed under Idris erasure. (Coq was unaffected — `Prop` indices erase |
| 40 | +-- without blocking proofs; `progress` was unaffected — it never recurses into |
| 41 | +-- those bodies.) |
| 42 | +-- |
| 43 | +-- FIX (Option A): `THLet`/`THCase`/`THLetPair` now carry their bound types as |
| 44 | +-- explicit, runtime-relevant fields — the ADR-003 pattern already used for the |
| 45 | +-- usage splits (`THApp`/`THTensor`). `progress` was re-verified against the new |
| 46 | +-- fields; the build stays green. With the bound types available, all 14 |
| 47 | +-- `htShift` cases typecheck and the lemma is total (below). |
34 | 48 |
|
35 | 49 | module Substitution |
36 | 50 |
|
@@ -211,11 +225,11 @@ shapeType g (With t1 t2) (THWith h1 h2) = shapeType g t1 h1 |
211 | 225 | shapeType g (Fst t1) (THFst h) = shapeType g t1 h |
212 | 226 | shapeType g (Snd t1) (THSnd h) = shapeType g t1 h |
213 | 227 | shapeType g (Tensor t1 t2) (THTensor d1 d2 h1 h2 prf) = trans (uaddLen d1 d2 _ prf) (shapeType g t1 h1) |
214 | | -shapeType g (LetPair t1 t2)(THLetPair d1 d2 h1 hb prf)= trans (uaddLen d1 d2 _ prf) (shapeType g t1 h1) |
| 228 | +shapeType g (LetPair t1 t2)(THLetPair d1 d2 _ _ h1 hb prf)= trans (uaddLen d1 d2 _ prf) (shapeType g t1 h1) |
215 | 229 | shapeType g (Inl b t1) (THInl h) = shapeType g t1 h |
216 | 230 | shapeType g (Inr a t1) (THInr h) = shapeType g t1 h |
217 | | -shapeType g (Case t tL tR) (THCase d1 d2 h hL hR prf) = trans (uaddLen d1 d2 _ prf) (shapeType g t h) |
218 | | -shapeType g (Let q t1 t2) (THLet d1 d2 _ h1 h2 prf) = |
| 231 | +shapeType g (Case t tL tR) (THCase d1 d2 _ _ h hL hR prf) = trans (uaddLen d1 d2 _ prf) (shapeType g t h) |
| 232 | +shapeType g (Let q t1 t2) (THLet d1 d2 _ _ h1 h2 prf) = |
219 | 233 | trans (uaddLen (uscale q d1) d2 _ prf) (trans (uscaleLen q d1) (shapeType g t1 h1)) |
220 | 234 | shapeType g (MkEcho m a b t1) (THEcho h) = shapeType g t1 h |
221 | 235 | shapeType g (Weaken t1) (THWeaken h) = shapeType g t1 h |
@@ -309,3 +323,167 @@ hvShift (TSnoc i' a') g c dg (USnoc di' qd) (S n0) hlen hv = |
309 | 323 | hv'' = rewrite hdgdi in rewrite predEq' hn in hv' |
310 | 324 | ih = hvShift i' g c dg di' n0 (predEq' hlen) hv'' |
311 | 325 | in rewrite hqd in HVThere ih |
| 326 | +
|
| 327 | +------------------------------------------------------------ |
| 328 | +-- 4b (cont). Term weakening: htShift |
| 329 | +------------------------------------------------------------ |
| 330 | +
|
| 331 | +trueNotFalse : True = False -> Void |
| 332 | +trueNotFalse Refl impossible |
| 333 | +
|
| 334 | +||| `shiftIdx` vs the kernel `<`, split by the boolean (avoids the surface-form |
| 335 | +||| mismatch `n < c` vs `compareNat n c == LT` that breaks `rewrite`). |
| 336 | +shiftIdxTrue : (c, n : Nat) -> (n < c) = True -> shiftIdx c n = n |
| 337 | +shiftIdxTrue Z n prf = void (trueNotFalse (trans (sym prf) (nLtZero n))) |
| 338 | +shiftIdxTrue (S c) Z prf = Refl |
| 339 | +shiftIdxTrue (S c) (S n) prf = cong S (shiftIdxTrue c n prf) |
| 340 | +
|
| 341 | +shiftIdxFalse : (c, n : Nat) -> (n < c) = False -> shiftIdx c n = S n |
| 342 | +shiftIdxFalse Z n prf = Refl |
| 343 | +shiftIdxFalse (S c) Z prf = void (trueNotFalse prf) |
| 344 | +shiftIdxFalse (S c) (S n) prf = cong S (shiftIdxFalse c n prf) |
| 345 | +
|
| 346 | +||| The kernel `shift` on a variable equals `Var` of the structural `shiftIdx`. |
| 347 | +public export |
| 348 | +shiftVarLemma : (c, n : Nat) -> shift c (Var n) = Var (shiftIdx c n) |
| 349 | +shiftVarLemma c n with (n < c) proof prf |
| 350 | + shiftVarLemma c n | True = rewrite shiftIdxTrue c n prf in Refl |
| 351 | + shiftVarLemma c n | False = rewrite shiftIdxFalse c n prf in Refl |
| 352 | +
|
| 353 | +||| UnitT inversion (its usage `uzero g` is not a free field; direct `case` |
| 354 | +||| would be stuck, same as `HVHere`). Also yields the type equation, since |
| 355 | +||| the caller's result type is not yet refined to `TUnit`. |
| 356 | +public export |
| 357 | +unitInv : Has g dd UnitT aa -> (dd = uzero g, aa = TUnit) |
| 358 | +unitInv THUnit = (Refl, Refl) |
| 359 | + |
| 360 | +||| Split a derivation's usage along the `G`/`I` append boundary via the shape |
| 361 | +||| invariant. `g`,`i`,`t` relevant (shapeType needs the context + term). |
| 362 | +public export |
| 363 | +usplitLemma : (g, i : Tctx) -> (dd : Uvec) -> (t : Tm) -> Has (tappend g i) dd t a |
| 364 | + -> (dg : Uvec ** di : Uvec ** (dd = uappend dg di, ulen di = tlen i)) |
| 365 | +usplitLemma g i dd t h = |
| 366 | + uappendSplit (tlen i) dd |
| 367 | + (rewrite trans (shapeType (tappend g i) t h) (tappendLen g i) in |
| 368 | + rewrite plusCommutative (tlen g) (tlen i) in lteAddRight (tlen i)) |
| 369 | + |
| 370 | +||| Boundary-insert: add two `(USnoc _ Zero)`-headed appends. |
| 371 | +public export |
| 372 | +uaddUshift : (ag, ai, bg, bi, cg, ci : Uvec) |
| 373 | + -> uadd ag bg = Just cg -> uadd ai bi = Just ci |
| 374 | + -> uadd (uappend (USnoc ag Zero) ai) (uappend (USnoc bg Zero) bi) |
| 375 | + = Just (uappend (USnoc cg Zero) ci) |
| 376 | +uaddUshift ag ai bg bi cg ci hg hi = |
| 377 | + uaddUappend ai bi ci (USnoc ag Zero) (USnoc bg Zero) (USnoc cg Zero) |
| 378 | + hi (rewrite hg in Refl) |
| 379 | + |
| 380 | +||| Scaling commutes with the boundary-insert. |
| 381 | +public export |
| 382 | +ushiftUscale : (q : Q) -> (dg, di : Uvec) |
| 383 | + -> uscale q (uappend (USnoc dg Zero) di) |
| 384 | + = uappend (USnoc (uscale q dg) Zero) (uscale q di) |
| 385 | +ushiftUscale q dg di = |
| 386 | + rewrite uscaleUappend q (USnoc dg Zero) di in rewrite qMulZeroR q in Refl |
| 387 | + |
| 388 | +------------------------------------------------------------ |
| 389 | +-- 4b (cont). Term weakening: htShift (open-context shift) |
| 390 | +------------------------------------------------------------ |
| 391 | + |
| 392 | +||| Insert a fresh `Zero`-usage binder `c` at cutoff `tlen i` into a typing |
| 393 | +||| derivation, shifting the term by `shift (tlen i)`. The general (prefix `i`) |
| 394 | +||| form is what the under-binder substitution induction needs. |
| 395 | +||| |
| 396 | +||| The binder cases recurse on the body in a context extended by the bound |
| 397 | +||| type. `Lam` reads its type from the term; `Let`/`Case`/`LetPair` read theirs |
| 398 | +||| from the explicit type fields added to `THLet`/`THCase`/`THLetPair` (Option |
| 399 | +||| A — without them the extended context `TSnoc i <bound>` is unconstructible |
| 400 | +||| under Idris erasure). The usage-splitting rules decompose each premise's |
| 401 | +||| usage along the `G`/`I` boundary (`usplitLemma`/`uappendSplit` + the |
| 402 | +||| `(Refl, _)` let-pattern performs the substitution), split the `uadd` premise |
| 403 | +||| with `uaddSplitBoundary`, and reassemble with the boundary insert |
| 404 | +||| `uaddUshift` (composing `ushiftUscale` for the `q`-scaled legs of App/Let). |
| 405 | +public export |
| 406 | +htShift : (i, g : Tctx) -> (c : Ty) -> (dg, di : Uvec) -> (t : Tm) |
| 407 | + -> ulen di = tlen i |
| 408 | + -> Has (tappend g i) (uappend dg di) t a |
| 409 | + -> Has (tappend (TSnoc g c) i) (uappend (USnoc dg Zero) di) |
| 410 | + (shift (tlen i) t) a |
| 411 | +htShift i g c dg di (Var n) hlen (THVar hv) = |
| 412 | + rewrite shiftVarLemma (tlen i) n in |
| 413 | + THVar (hvShift i g c dg di n hlen hv) |
| 414 | +htShift i g c dg di UnitT hlen h = |
| 415 | + let (hd, ha) = unitInv h |
| 416 | + (hdg, hdi) = uappendInj di (uzero i) dg (uzero g) |
| 417 | + (trans hlen (sym (uzeroLen i))) |
| 418 | + (trans hd (uzeroTappend g i)) |
| 419 | + in rewrite ha in rewrite hdg in rewrite hdi in |
| 420 | + rewrite sym (uzeroTappend (TSnoc g c) i) in THUnit |
| 421 | +htShift i g c dg di (Lam q a' body) hlen (THLam bodyD) = |
| 422 | + THLam (htShift (TSnoc i a') g c dg (USnoc di q) body (cong S hlen) bodyD) |
| 423 | +htShift i g c dg di (App t1 t2) hlen (THApp d1 d2 q h1 h2 prf) = |
| 424 | + let (d1g ** d1i ** (Refl, l1)) = usplitLemma g i d1 t1 h1 |
| 425 | + (d2g ** d2i ** (Refl, l2)) = usplitLemma g i d2 t2 h2 |
| 426 | + (hg, hi) = uaddSplitBoundary d1g d1i (uscale q d2g) (uscale q d2i) dg di |
| 427 | + (trans l1 (sym (trans (uscaleLen q d2i) l2))) |
| 428 | + (trans hlen (sym l1)) |
| 429 | + (rewrite sym (uscaleUappend q d2g d2i) in prf) |
| 430 | + in THApp (uappend (USnoc d1g Zero) d1i) (uappend (USnoc d2g Zero) d2i) q |
| 431 | + (htShift i g c d1g d1i t1 l1 h1) |
| 432 | + (htShift i g c d2g d2i t2 l2 h2) |
| 433 | + (rewrite ushiftUscale q d2g d2i in |
| 434 | + uaddUshift d1g d1i (uscale q d2g) (uscale q d2i) dg di hg hi) |
| 435 | +htShift i g c dg di (With t1 t2) hlen (THWith h1 h2) = |
| 436 | + THWith (htShift i g c dg di t1 hlen h1) (htShift i g c dg di t2 hlen h2) |
| 437 | +htShift i g c dg di (Fst t) hlen (THFst h) = THFst (htShift i g c dg di t hlen h) |
| 438 | +htShift i g c dg di (Snd t) hlen (THSnd h) = THSnd (htShift i g c dg di t hlen h) |
| 439 | +htShift i g c dg di (Tensor t1 t2) hlen (THTensor d1 d2 h1 h2 prf) = |
| 440 | + let (d1g ** d1i ** (Refl, l1)) = usplitLemma g i d1 t1 h1 |
| 441 | + (d2g ** d2i ** (Refl, l2)) = usplitLemma g i d2 t2 h2 |
| 442 | + (hg, hi) = uaddSplitBoundary d1g d1i d2g d2i dg di |
| 443 | + (trans l1 (sym l2)) (trans hlen (sym l1)) prf |
| 444 | + in THTensor (uappend (USnoc d1g Zero) d1i) (uappend (USnoc d2g Zero) d2i) |
| 445 | + (htShift i g c d1g d1i t1 l1 h1) |
| 446 | + (htShift i g c d2g d2i t2 l2 h2) |
| 447 | + (uaddUshift d1g d1i d2g d2i dg di hg hi) |
| 448 | +htShift i g c dg di (LetPair t1 t2) hlen (THLetPair d1 d2 a' b' h1 hb prf) = |
| 449 | + let (d1g ** d1i ** (Refl, l1)) = usplitLemma g i d1 t1 h1 |
| 450 | + (d2g ** d2i ** (Refl, l2)) = uappendSplit (tlen i) d2 |
| 451 | + (rewrite trans (predEq' (predEq' (shapeType (TSnoc (TSnoc (tappend g i) a') b') t2 hb))) (tappendLen g i) in |
| 452 | + rewrite plusCommutative (tlen g) (tlen i) in lteAddRight (tlen i)) |
| 453 | + (hg, hi) = uaddSplitBoundary d1g d1i d2g d2i dg di |
| 454 | + (trans l1 (sym l2)) (trans hlen (sym l1)) prf |
| 455 | + in THLetPair (uappend (USnoc d1g Zero) d1i) (uappend (USnoc d2g Zero) d2i) a' b' |
| 456 | + (htShift i g c d1g d1i t1 l1 h1) |
| 457 | + (htShift (TSnoc (TSnoc i a') b') g c d2g (USnoc (USnoc d2i One) One) t2 |
| 458 | + (cong S (cong S l2)) hb) |
| 459 | + (uaddUshift d1g d1i d2g d2i dg di hg hi) |
| 460 | +htShift i g c dg di (Inl b0 t) hlen (THInl h) = THInl (htShift i g c dg di t hlen h) |
| 461 | +htShift i g c dg di (Inr a0 t) hlen (THInr h) = THInr (htShift i g c dg di t hlen h) |
| 462 | +htShift i g c dg di (Case t tL tR) hlen (THCase d1 d2 a' b' h hL hR prf) = |
| 463 | + let (d1g ** d1i ** (Refl, l1)) = usplitLemma g i d1 t h |
| 464 | + (d2g ** d2i ** (Refl, l2)) = uappendSplit (tlen i) d2 |
| 465 | + (rewrite trans (predEq' (shapeType (TSnoc (tappend g i) a') tL hL)) (tappendLen g i) in |
| 466 | + rewrite plusCommutative (tlen g) (tlen i) in lteAddRight (tlen i)) |
| 467 | + (hg, hi) = uaddSplitBoundary d1g d1i d2g d2i dg di |
| 468 | + (trans l1 (sym l2)) (trans hlen (sym l1)) prf |
| 469 | + in THCase (uappend (USnoc d1g Zero) d1i) (uappend (USnoc d2g Zero) d2i) a' b' |
| 470 | + (htShift i g c d1g d1i t l1 h) |
| 471 | + (htShift (TSnoc i a') g c d2g (USnoc d2i One) tL (cong S l2) hL) |
| 472 | + (htShift (TSnoc i b') g c d2g (USnoc d2i One) tR (cong S l2) hR) |
| 473 | + (uaddUshift d1g d1i d2g d2i dg di hg hi) |
| 474 | +htShift i g c dg di (Let q t1 t2) hlen (THLet d1 d2 _ a' h1 h2 prf) = |
| 475 | + let (d1g ** d1i ** (Refl, l1)) = usplitLemma g i d1 t1 h1 |
| 476 | + (d2g ** d2i ** (Refl, l2)) = uappendSplit (tlen i) d2 |
| 477 | + (rewrite trans (predEq' (shapeType (TSnoc (tappend g i) a') t2 h2)) (tappendLen g i) in |
| 478 | + rewrite plusCommutative (tlen g) (tlen i) in lteAddRight (tlen i)) |
| 479 | + (hg, hi) = uaddSplitBoundary (uscale q d1g) (uscale q d1i) d2g d2i dg di |
| 480 | + (trans (uscaleLen q d1i) (trans l1 (sym l2))) |
| 481 | + (trans hlen (sym (trans (uscaleLen q d1i) l1))) |
| 482 | + (rewrite sym (uscaleUappend q d1g d1i) in prf) |
| 483 | + in THLet (uappend (USnoc d1g Zero) d1i) (uappend (USnoc d2g Zero) d2i) q a' |
| 484 | + (htShift i g c d1g d1i t1 l1 h1) |
| 485 | + (htShift (TSnoc i a') g c d2g (USnoc d2i q) t2 (cong S l2) h2) |
| 486 | + (rewrite ushiftUscale q d1g d1i in |
| 487 | + uaddUshift (uscale q d1g) (uscale q d1i) d2g d2i dg di hg hi) |
| 488 | +htShift i g c dg di (MkEcho m aE bE t) hlen (THEcho h) = THEcho (htShift i g c dg di t hlen h) |
| 489 | +htShift i g c dg di (Weaken t) hlen (THWeaken h) = THWeaken (htShift i g c dg di t hlen h) |
0 commit comments