|
5 | 5 | -- - Syntax: Expr inductive with Num, Str, Bool, Identity, BraidLit, |
6 | 6 | -- Compose (.), Tensor (|), Pipeline (>>), Close, Add, Eq, the echo |
7 | 7 | -- constructors EchoClose, Lower, Residue, EchoVal (structured loss), and |
8 | | --- the product constructors Pair, Fst, Snd, EchoAdd |
| 8 | +-- the product constructors Pair, Fst, Snd, EchoAdd, EchoEq |
9 | 9 | -- - Typing: HasType inductive relation covering T-Num, T-Str, T-Bool, |
10 | 10 | -- T-Identity, T-Braid, T-Compose-Word, T-Tensor-Word, T-Pipeline, |
11 | 11 | -- T-Close-Word, T-Add-Num, T-Eq-Word, T-Eq-Num, T-Eq-Str, the echo |
12 | | --- rules T-Echo-Close, T-Lower, T-Residue, T-Echo-Val, and the product |
13 | | --- rules T-Pair, T-Fst, T-Snd, T-Echo-Add |
14 | | --- - Semantics: Small-step Step relation (47 rules incl. echo + product) |
| 12 | +-- rules T-Echo-Close, T-Lower, T-Residue, T-Echo-Val, the product |
| 13 | +-- rules T-Pair, T-Fst, T-Snd, T-Echo-Add, and the echo-equality rules |
| 14 | +-- T-Echo-Eq-Word, T-Echo-Eq-Num, T-Echo-Eq-Str |
| 15 | +-- - Semantics: Small-step Step relation (55 rules incl. echo + product) |
15 | 16 | -- |
16 | 17 | -- Theorems proven: |
17 | 18 | -- 1. Progress: well-typed closed terms are values or can step |
|
26 | 27 | -- (hyperpolymath/echo-types: `Echo f y := Σ (x : A), f x ≡ y`) directly into |
27 | 28 | -- the type system: closing a braid through an echo retains the residue, so the |
28 | 29 | -- otherwise-irreversible `close` becomes reversible at the type level. The |
29 | | --- product type `Ty.prod ρ σ` carries a second lossy operation, `echoAdd`: |
30 | | --- ordinary `add` discards which two numbers were summed, but `echoAdd` keeps |
31 | | --- the summand pair as its residue (residue type `Num × Num`, result `Num`), so |
32 | | --- distinct summands that collapse to the same sum stay distinguishable. See the |
33 | | --- §ECHO-TYPES section at the foot of the file for the residue-recovery and |
34 | | --- non-injectivity theorems (both the `close` and `echoAdd` forms). |
| 30 | +-- product type `Ty.prod ρ σ` carries two further lossy operations, `echoAdd` |
| 31 | +-- and `echoEq`: ordinary `add` discards which two numbers were summed, but |
| 32 | +-- `echoAdd` keeps the summand pair as its residue (residue type `Num × Num`, |
| 33 | +-- result `Num`); ordinary `eq` discards which two operands were compared, but |
| 34 | +-- `echoEq` keeps the operand pair as its residue (residue type `ρ × ρ`, result |
| 35 | +-- `Bool`), so distinct inputs that collapse to the same sum or boolean stay |
| 36 | +-- distinguishable. See the §ECHO-TYPES section at the foot of the file for the |
| 37 | +-- residue-recovery and non-injectivity theorems (the `close`, `echoAdd`, and |
| 38 | +-- `echoEq` forms). |
35 | 39 | -- |
36 | 40 | -- Note on T-Let: the let binding requires a generalized de Bruijn substitution |
37 | 41 | -- lemma (standard POPLmark machinery); tracked as TG-1. The fragment here |
@@ -99,6 +103,7 @@ inductive Expr where |
99 | 103 | | fst : Expr → Expr -- first projection |
100 | 104 | | snd : Expr → Expr -- second projection |
101 | 105 | | echoAdd : Expr → Expr → Expr -- echo-preserving addition (residue = pair of summands) |
| 106 | + | echoEq : Expr → Expr → Expr -- echo-preserving equality (residue = operand pair) |
102 | 107 | deriving DecidableEq, Repr |
103 | 108 |
|
104 | 109 | /-- Value predicate: fully reduced expressions. -/ |
@@ -197,6 +202,15 @@ inductive HasType : Ctx → Expr → Ty → Prop where |
197 | 202 | | tEchoAdd (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Add] |
198 | 203 | HasType Γ e₁ .num → HasType Γ e₂ .num → |
199 | 204 | HasType Γ (.echoAdd e₁ e₂) (.echo (.prod .num .num) .num) |
| 205 | + | tEchoEqWord (Γ : Ctx) (e₁ e₂ : Expr) (n : Nat) : -- [T-Echo-Eq-Word] |
| 206 | + HasType Γ e₁ (.word n) → HasType Γ e₂ (.word n) → |
| 207 | + HasType Γ (.echoEq e₁ e₂) (.echo (.prod (.word n) (.word n)) .bool) |
| 208 | + | tEchoEqNum (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Eq-Num] |
| 209 | + HasType Γ e₁ .num → HasType Γ e₂ .num → |
| 210 | + HasType Γ (.echoEq e₁ e₂) (.echo (.prod .num .num) .bool) |
| 211 | + | tEchoEqStr (Γ : Ctx) (e₁ e₂ : Expr) : -- [T-Echo-Eq-Str] |
| 212 | + HasType Γ e₁ .str → HasType Γ e₂ .str → |
| 213 | + HasType Γ (.echoEq e₁ e₂) (.echo (.prod .str .str) .bool) |
200 | 214 |
|
201 | 215 | -- ═══════════════════════════════════════════════════════════════════════ |
202 | 216 | -- SMALL-STEP SEMANTICS |
@@ -267,6 +281,23 @@ inductive Step : Expr → Expr → Prop where |
267 | 281 | | echoAddRight : IsValue e₁ → Step e₂ e₂' → Step (.echoAdd e₁ e₂) (.echoAdd e₁ e₂') |
268 | 282 | | echoAddNums : Step (.echoAdd (.num n₁) (.num n₂)) |
269 | 283 | (.echoVal (.pair (.num n₁) (.num n₂)) (.num (n₁ + n₂))) |
| 284 | + -- Echo-preserving equality: residue retains the operand pair; result is the |
| 285 | + -- boolean. Mirrors the 8 `eq` rules; each computation produces |
| 286 | + -- `echoVal (pair <operands>) (boolLit <same bool as the matching eq rule>)`. |
| 287 | + | echoEqLeft : Step e₁ e₁' → Step (.echoEq e₁ e₂) (.echoEq e₁' e₂) |
| 288 | + | echoEqRight : IsValue e₁ → Step e₂ e₂' → Step (.echoEq e₁ e₂) (.echoEq e₁ e₂') |
| 289 | + | echoEqNums : Step (.echoEq (.num n₁) (.num n₂)) |
| 290 | + (.echoVal (.pair (.num n₁) (.num n₂)) (.boolLit (n₁ == n₂))) |
| 291 | + | echoEqStrs : Step (.echoEq (.str s₁) (.str s₂)) |
| 292 | + (.echoVal (.pair (.str s₁) (.str s₂)) (.boolLit (s₁ == s₂))) |
| 293 | + | echoEqBraids : Step (.echoEq (.braidLit gs₁) (.braidLit gs₂)) |
| 294 | + (.echoVal (.pair (.braidLit gs₁) (.braidLit gs₂)) (.boolLit (gs₁ == gs₂))) |
| 295 | + | echoEqIdId : Step (.echoEq .identity .identity) |
| 296 | + (.echoVal (.pair .identity .identity) (.boolLit true)) |
| 297 | + | echoEqIdBraid : Step (.echoEq .identity (.braidLit gs)) |
| 298 | + (.echoVal (.pair .identity (.braidLit gs)) (.boolLit (gs == []))) |
| 299 | + | echoEqBraidId : Step (.echoEq (.braidLit gs) .identity) |
| 300 | + (.echoVal (.pair (.braidLit gs) .identity) (.boolLit (gs == []))) |
270 | 301 |
|
271 | 302 | -- ═══════════════════════════════════════════════════════════════════════ |
272 | 303 | -- LEMMAS |
@@ -511,6 +542,36 @@ theorem progress : HasType [] e τ → IsValue e ∨ ∃ e', Step e e' := by |
511 | 542 | exact ⟨_, .echoAddNums⟩ |
512 | 543 | · exact ⟨_, .echoAddRight hv₁ hs₂⟩ |
513 | 544 | · exact ⟨_, .echoAddLeft hs₁⟩ |
| 545 | + | tEchoEqWord _ _ n h₁ h₂ => |
| 546 | + right |
| 547 | + rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩ |
| 548 | + · rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩ |
| 549 | + · rcases canonical_word hv₁ h₁ with ⟨rfl, _⟩ | ⟨gs₁, rfl, _⟩ <;> |
| 550 | + rcases canonical_word hv₂ h₂ with ⟨rfl, _⟩ | ⟨gs₂, rfl, _⟩ |
| 551 | + · exact ⟨_, .echoEqIdId⟩ |
| 552 | + · exact ⟨_, .echoEqIdBraid⟩ |
| 553 | + · exact ⟨_, .echoEqBraidId⟩ |
| 554 | + · exact ⟨_, .echoEqBraids⟩ |
| 555 | + · exact ⟨_, .echoEqRight hv₁ hs₂⟩ |
| 556 | + · exact ⟨_, .echoEqLeft hs₁⟩ |
| 557 | + | tEchoEqNum _ _ h₁ h₂ => |
| 558 | + right |
| 559 | + rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩ |
| 560 | + · rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩ |
| 561 | + · obtain ⟨n₁, rfl⟩ := canonical_num hv₁ h₁ |
| 562 | + obtain ⟨n₂, rfl⟩ := canonical_num hv₂ h₂ |
| 563 | + exact ⟨_, .echoEqNums⟩ |
| 564 | + · exact ⟨_, .echoEqRight hv₁ hs₂⟩ |
| 565 | + · exact ⟨_, .echoEqLeft hs₁⟩ |
| 566 | + | tEchoEqStr _ _ h₁ h₂ => |
| 567 | + right |
| 568 | + rcases progress h₁ with hv₁ | ⟨e₁', hs₁⟩ |
| 569 | + · rcases progress h₂ with hv₂ | ⟨e₂', hs₂⟩ |
| 570 | + · obtain ⟨s₁, rfl⟩ := canonical_str hv₁ h₁ |
| 571 | + obtain ⟨s₂, rfl⟩ := canonical_str hv₂ h₂ |
| 572 | + exact ⟨_, .echoEqStrs⟩ |
| 573 | + · exact ⟨_, .echoEqRight hv₁ hs₂⟩ |
| 574 | + · exact ⟨_, .echoEqLeft hs₁⟩ |
514 | 575 |
|
515 | 576 | -- ═══════════════════════════════════════════════════════════════════════ |
516 | 577 | -- THEOREM 2: PRESERVATION |
@@ -644,6 +705,50 @@ theorem preservation : HasType [] e τ → Step e e' → HasType [] e' τ := by |
644 | 705 | | echoAddNums => |
645 | 706 | cases ht with | tEchoAdd _ _ h₁ h₂ => |
646 | 707 | exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tNum _ _) (.tNum _ _)) (.tNum _ _) |
| 708 | + -- Echo-preserving equality: congruence rebuilds via `tEchoEq*` + `ih` (the |
| 709 | + -- inner type is ambiguous, so case-split on all three `tEchoEq*`); the 6 |
| 710 | + -- computation rules invert the matching `tEchoEq*` and build the formed echo |
| 711 | + -- value `echoVal (pair <ops>) (boolLit …)`, residue typed via `tPair`. |
| 712 | + | echoEqLeft hs ih => |
| 713 | + cases ht with |
| 714 | + | tEchoEqWord _ _ n h₁ h₂ => exact .tEchoEqWord _ _ _ n (ih h₁) h₂ |
| 715 | + | tEchoEqNum _ _ h₁ h₂ => exact .tEchoEqNum _ _ _ (ih h₁) h₂ |
| 716 | + | tEchoEqStr _ _ h₁ h₂ => exact .tEchoEqStr _ _ _ (ih h₁) h₂ |
| 717 | + | echoEqRight _ hs ih => |
| 718 | + cases ht with |
| 719 | + | tEchoEqWord _ _ n h₁ h₂ => exact .tEchoEqWord _ _ _ n h₁ (ih h₂) |
| 720 | + | tEchoEqNum _ _ h₁ h₂ => exact .tEchoEqNum _ _ _ h₁ (ih h₂) |
| 721 | + | tEchoEqStr _ _ h₁ h₂ => exact .tEchoEqStr _ _ _ h₁ (ih h₂) |
| 722 | + | echoEqNums => cases ht with |
| 723 | + | tEchoEqNum => |
| 724 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tNum _ _) (.tNum _ _)) (.tBool _ _) |
| 725 | + | tEchoEqWord _ _ _ _ h₁ => cases h₁ |
| 726 | + | tEchoEqStr _ _ _ h₁ => cases h₁ |
| 727 | + | echoEqStrs => cases ht with |
| 728 | + | tEchoEqStr => |
| 729 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ (.tStr _ _) (.tStr _ _)) (.tBool _ _) |
| 730 | + | tEchoEqWord _ _ _ _ h₁ => cases h₁ |
| 731 | + | tEchoEqNum _ _ _ h₁ => cases h₁ |
| 732 | + | echoEqBraids => cases ht with |
| 733 | + | tEchoEqWord _ _ n h₁ h₂ => |
| 734 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _) |
| 735 | + | tEchoEqNum _ _ _ h₁ => cases h₁ |
| 736 | + | tEchoEqStr _ _ _ h₁ => cases h₁ |
| 737 | + | echoEqIdId => cases ht with |
| 738 | + | tEchoEqWord _ _ n h₁ h₂ => |
| 739 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _) |
| 740 | + | tEchoEqNum _ _ _ h₁ => cases h₁ |
| 741 | + | tEchoEqStr _ _ _ h₁ => cases h₁ |
| 742 | + | echoEqIdBraid => cases ht with |
| 743 | + | tEchoEqWord _ _ n h₁ h₂ => |
| 744 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _) |
| 745 | + | tEchoEqNum _ _ _ h₁ => cases h₁ |
| 746 | + | tEchoEqStr _ _ _ h₁ => cases h₁ |
| 747 | + | echoEqBraidId => cases ht with |
| 748 | + | tEchoEqWord _ _ n h₁ h₂ => |
| 749 | + exact .tEchoVal _ _ _ _ _ (.tPair _ _ _ _ _ h₁ h₂) (.tBool _ _) |
| 750 | + | tEchoEqNum _ _ _ h₁ => cases h₁ |
| 751 | + | tEchoEqStr _ _ _ h₁ => cases h₁ |
647 | 752 |
|
648 | 753 | -- ═══════════════════════════════════════════════════════════════════════ |
649 | 754 | -- THEOREM 3: DETERMINISM |
@@ -841,6 +946,51 @@ theorem determinism : Step e e₁ → Step e e₂ → e₁ = e₂ := by |
841 | 946 | | echoAddLeft h => exact absurd h (value_no_step (.num _)) |
842 | 947 | | echoAddRight _ h => exact absurd h (value_no_step (.num _)) |
843 | 948 | | echoAddNums => rfl |
| 949 | + -- Echo-preserving equality: same shape as `eq` determinism — congruence is |
| 950 | + -- deterministic by IH; computations discharge congruence races via |
| 951 | + -- `value_no_step` on the atomic operand values; same-rule → `rfl`. |
| 952 | + | echoEqLeft hs ih => cases hs₂ with |
| 953 | + | echoEqLeft h => rw [ih h] |
| 954 | + | echoEqRight hv _ => exact absurd hs (value_no_step hv) |
| 955 | + | echoEqNums => exact absurd hs (value_no_step (.num _)) |
| 956 | + | echoEqStrs => exact absurd hs (value_no_step (.str _)) |
| 957 | + | echoEqBraids => exact absurd hs (value_no_step (.braidLit _)) |
| 958 | + | echoEqIdId => exact absurd hs (value_no_step .identity) |
| 959 | + | echoEqIdBraid => exact absurd hs (value_no_step .identity) |
| 960 | + | echoEqBraidId => exact absurd hs (value_no_step (.braidLit _)) |
| 961 | + | echoEqRight hv hs ih => cases hs₂ with |
| 962 | + | echoEqLeft h => exact absurd h (value_no_step hv) |
| 963 | + | echoEqRight _ h => exact congrArg (Expr.echoEq _ ·) (ih h) |
| 964 | + | echoEqNums => exact absurd hs (value_no_step (.num _)) |
| 965 | + | echoEqStrs => exact absurd hs (value_no_step (.str _)) |
| 966 | + | echoEqBraids => exact absurd hs (value_no_step (.braidLit _)) |
| 967 | + | echoEqIdId => cases hv with | identity => exact absurd hs (value_no_step .identity) |
| 968 | + | echoEqIdBraid => cases hv with | identity => exact absurd hs (value_no_step (.braidLit _)) |
| 969 | + | echoEqBraidId => cases hv with | braidLit => exact absurd hs (value_no_step .identity) |
| 970 | + | echoEqNums => cases hs₂ with |
| 971 | + | echoEqLeft h => exact absurd h (value_no_step (.num _)) |
| 972 | + | echoEqRight _ h => exact absurd h (value_no_step (.num _)) |
| 973 | + | echoEqNums => rfl |
| 974 | + | echoEqStrs => cases hs₂ with |
| 975 | + | echoEqLeft h => exact absurd h (value_no_step (.str _)) |
| 976 | + | echoEqRight _ h => exact absurd h (value_no_step (.str _)) |
| 977 | + | echoEqStrs => rfl |
| 978 | + | echoEqBraids => cases hs₂ with |
| 979 | + | echoEqLeft h => exact absurd h (value_no_step (.braidLit _)) |
| 980 | + | echoEqRight _ h => exact absurd h (value_no_step (.braidLit _)) |
| 981 | + | echoEqBraids => rfl |
| 982 | + | echoEqIdId => cases hs₂ with |
| 983 | + | echoEqLeft h => exact absurd h (value_no_step .identity) |
| 984 | + | echoEqRight _ h => exact absurd h (value_no_step .identity) |
| 985 | + | echoEqIdId => rfl |
| 986 | + | echoEqIdBraid => cases hs₂ with |
| 987 | + | echoEqLeft h => exact absurd h (value_no_step .identity) |
| 988 | + | echoEqRight _ h => exact absurd h (value_no_step (.braidLit _)) |
| 989 | + | echoEqIdBraid => rfl |
| 990 | + | echoEqBraidId => cases hs₂ with |
| 991 | + | echoEqLeft h => exact absurd h (value_no_step (.braidLit _)) |
| 992 | + | echoEqRight _ h => exact absurd h (value_no_step .identity) |
| 993 | + | echoEqBraidId => rfl |
844 | 994 |
|
845 | 995 | -- ═══════════════════════════════════════════════════════════════════════ |
846 | 996 | -- COROLLARY: TYPE SAFETY |
@@ -932,6 +1082,16 @@ theorem echoAdd_distinguishes : |
932 | 1082 | (Expr.pair (.num 1) (.num 3) ≠ Expr.pair (.num 2) (.num 2)) := |
933 | 1083 | ⟨⟨echoAdd_lower_sums 1 3, echoAdd_lower_sums 2 2⟩, by decide⟩ |
934 | 1084 |
|
| 1085 | +/-- **Echo distinguishes what `eq` collapses.** 1≟2 and 3≟4 both lower to |
| 1086 | + `false`, but their residues (the operand pairs) stay distinct. -/ |
| 1087 | +theorem echoEq_distinguishes : |
| 1088 | + (StepStar (.lower (.echoEq (.num 1) (.num 2))) (.boolLit (1 == 2)) ∧ |
| 1089 | + StepStar (.lower (.echoEq (.num 3) (.num 4))) (.boolLit (3 == 4))) ∧ |
| 1090 | + (Expr.pair (.num 1) (.num 2) ≠ Expr.pair (.num 3) (.num 4)) := |
| 1091 | + ⟨⟨.head (.lowerStep .echoEqNums) (.head (.lowerVal (.pair (.num _) (.num _)) (.boolLit _)) .refl), |
| 1092 | + .head (.lowerStep .echoEqNums) (.head (.lowerVal (.pair (.num _) (.num _)) (.boolLit _)) .refl)⟩, |
| 1093 | + by decide⟩ |
| 1094 | + |
935 | 1095 | -- ═══════════════════════════════════════════════════════════════════════ |
936 | 1096 | -- TG-2: DECIDABILITY OF TYPE CHECKING |
937 | 1097 | -- ═══════════════════════════════════════════════════════════════════════ |
@@ -1008,6 +1168,12 @@ def infer (Γ : Ctx) : Expr → Option Ty |
1008 | 1168 | match infer Γ e₁, infer Γ e₂ with |
1009 | 1169 | | some .num, some .num => some (.echo (.prod .num .num) .num) |
1010 | 1170 | | _, _ => none |
| 1171 | + | .echoEq e₁ e₂ => |
| 1172 | + match infer Γ e₁, infer Γ e₂ with |
| 1173 | + | some (.word n), some (.word m) => if n = m then some (.echo (.prod (.word n) (.word n)) .bool) else none |
| 1174 | + | some .num, some .num => some (.echo (.prod .num .num) .bool) |
| 1175 | + | some .str, some .str => some (.echo (.prod .str .str) .bool) |
| 1176 | + | _, _ => none |
1011 | 1177 |
|
1012 | 1178 | /-- **Completeness**: every typing derivation is computed by `infer`. -/ |
1013 | 1179 | theorem infer_complete {Γ : Ctx} {e : Expr} {τ : Ty} : |
@@ -1093,6 +1259,17 @@ theorem infer_sound {Γ : Ctx} {e : Expr} {τ : Ty} : |
1093 | 1259 | intro h; simp only [infer] at h; split at h |
1094 | 1260 | next he₁ he₂ => injection h with h; subst h; exact .tEchoAdd _ _ _ (ih₁ he₁) (ih₂ he₂) |
1095 | 1261 | all_goals simp at h |
| 1262 | + | echoEq e₁ e₂ ih₁ ih₂ => |
| 1263 | + intro h; simp only [infer] at h; split at h |
| 1264 | + next n m he₁ he₂ => |
| 1265 | + split at h |
| 1266 | + next hnm => |
| 1267 | + injection h with h; subst h; subst hnm |
| 1268 | + exact .tEchoEqWord _ _ _ _ (ih₁ he₁) (ih₂ he₂) |
| 1269 | + next => simp at h |
| 1270 | + next he₁ he₂ => injection h with h; subst h; exact .tEchoEqNum _ _ _ (ih₁ he₁) (ih₂ he₂) |
| 1271 | + next he₁ he₂ => injection h with h; subst h; exact .tEchoEqStr _ _ _ (ih₁ he₁) (ih₂ he₂) |
| 1272 | + all_goals simp at h |
1096 | 1273 |
|
1097 | 1274 | /-- **Decidability of type checking** (TG-2): `infer` decides `HasType`. -/ |
1098 | 1275 | theorem infer_iff_hasType {Γ : Ctx} {e : Expr} {τ : Ty} : |
|
0 commit comments