OctiveLean/Core/Preservation.lean — the TOC analogue of TGC's
preservation. Statement:
HasType Γ e T ∧ HasTypeEnv env Γ ∧ BigStep env e v env'
⟹ HasTypeV v T ∧ HasTypeEnv env' Γ
No heap-typing extension (Octave has no heap). Γ is unchanged across
big-steps (assign requires x already typed).
Three structural changes were required to make preservation provable
under env-mutation, all small:
* letIn semantics shifted to scope-restoring: BigStep.letInR now
returns env1 (the env after evaluating the bound expression)
rather than env2 (after the body). This drops body's mutations
at scope-end, matching the lambda-calculus tradition. Determinism
and Eval updated to match.
* HasTypeV.vClos uses a two-part premise (he_dom + he_typed)
instead of nested ∃ — the kernel rejects nested inductive
parameters with locally-bound vars. The two parts are equivalent
to HasTypeEnv via the new HasTypeV.vClos_to_env inversion lemma.
* Inversion via HasTypeV.vClos_to_env exposes the closure's typing
context as an existential — preservation's appR case uses this
to construct the body's HasTypeEnv via extend_letIn.
The cross-language symmetry that emerged:
TGC preservation : threads heap-typings, weakens via extension.
TOC preservation : threads env directly, no extension needed.
In both, the rule cases collapse into the same three structural
shapes — terminal, IH-chain, contradiction-collapse. The case bodies
differ in HOW state is propagated (heap-typing for TGC, env for TOC)
but the SHAPE of each case is identical. That's the cross-language
abstraction speaking.
Zero sorries / axioms / admits across both projects.
106 lines
3.3 KiB
Text
106 lines
3.3 KiB
Text
import OctiveLean.Core.Semantics
|
|
|
|
namespace OctiveLean.Core
|
|
|
|
/-! # Determinism of TOC big-step.
|
|
|
|
`BigStep env e v₁ env₁ → BigStep env e v₂ env₂ → v₁ = v₂ ∧ env₁ = env₂`
|
|
|
|
Proof structure mirrors TGC's `Determinism` line-for-line on the shared
|
|
ten constructors. Octave-specific cases (`assign`, `whileT`) follow the
|
|
same three patterns: terminal, structural-functional, contradiction-collapse.
|
|
|
|
The `whileFR`/`whileTR` cross-case is closed exactly like `ifTR`/`ifFR`:
|
|
the IH on the condition produces `vBool true = vBool false`, dispatched
|
|
by `Bool.noConfusion`. -/
|
|
|
|
theorem BigStep.deterministic
|
|
{env : Env} {e : Term} {v₁ v₂ : Value} {env₁ env₂ : Env}
|
|
(D₁ : BigStep env e v₁ env₁) (D₂ : BigStep env e v₂ env₂) :
|
|
v₁ = v₂ ∧ env₁ = env₂ := by
|
|
induction D₁ generalizing v₂ env₂ with
|
|
| unitR => cases D₂; exact ⟨rfl, rfl⟩
|
|
| intLitR n => cases D₂; exact ⟨rfl, rfl⟩
|
|
| boolLitR b => cases D₂; exact ⟨rfl, rfl⟩
|
|
| varR hLook =>
|
|
cases D₂ with
|
|
| varR hLook' =>
|
|
have heq := hLook.symm.trans hLook'
|
|
exact ⟨Option.some.inj heq, rfl⟩
|
|
| lamR x body => cases D₂; exact ⟨rfl, rfl⟩
|
|
| appR _ _ _ ih1 ih2 ihb =>
|
|
cases D₂ with
|
|
| appR D1' D2' Db' =>
|
|
have ⟨hClos, hE1⟩ := ih1 D1'
|
|
injection hClos with hx hbody henv
|
|
subst hx; subst hbody; subst henv; subst hE1
|
|
have ⟨hArg, hE2⟩ := ih2 D2'
|
|
subst hArg; subst hE2
|
|
have ⟨hv, _⟩ := ihb Db'
|
|
exact ⟨hv, rfl⟩
|
|
| letInR _ _ ih1 ih2 =>
|
|
cases D₂ with
|
|
| letInR D1' D2' =>
|
|
have ⟨hv1, hE1⟩ := ih1 D1'
|
|
subst hv1; subst hE1
|
|
have ⟨hv2, _⟩ := ih2 D2'
|
|
exact ⟨hv2, rfl⟩
|
|
| ifTR _ _ ihc iht =>
|
|
cases D₂ with
|
|
| ifTR Dc' Dt' =>
|
|
have ⟨_, hE1⟩ := ihc Dc'; subst hE1
|
|
exact iht Dt'
|
|
| ifFR Dc' _ =>
|
|
have ⟨hb, _⟩ := ihc Dc'
|
|
injection hb with hb_eq
|
|
exact Bool.noConfusion hb_eq
|
|
| ifFR _ _ ihc ihf =>
|
|
cases D₂ with
|
|
| ifTR Dc' _ =>
|
|
have ⟨hb, _⟩ := ihc Dc'
|
|
injection hb with hb_eq
|
|
exact Bool.noConfusion hb_eq
|
|
| ifFR Dc' Df' =>
|
|
have ⟨_, hE1⟩ := ihc Dc'; subst hE1
|
|
exact ihf Df'
|
|
| binopR _ _ Hop ih1 ih2 =>
|
|
cases D₂ with
|
|
| binopR D1' D2' Hop' =>
|
|
have ⟨hv1, hE1⟩ := ih1 D1'
|
|
subst hv1; subst hE1
|
|
have ⟨hv2, hE2⟩ := ih2 D2'
|
|
subst hv2; subst hE2
|
|
have heq := Hop.symm.trans Hop'
|
|
exact ⟨Option.some.inj heq, rfl⟩
|
|
| seqR _ _ ih1 ih2 =>
|
|
cases D₂ with
|
|
| seqR D1' D2' =>
|
|
have ⟨_, hE1⟩ := ih1 D1'; subst hE1
|
|
exact ih2 D2'
|
|
| assignR _ ih =>
|
|
cases D₂ with
|
|
| assignR D' =>
|
|
have ⟨hv, hE⟩ := ih D'
|
|
subst hv; subst hE
|
|
exact ⟨rfl, rfl⟩
|
|
| whileFR _ ihc =>
|
|
cases D₂ with
|
|
| whileFR Dc' =>
|
|
have ⟨_, hE⟩ := ihc Dc'; subst hE
|
|
exact ⟨rfl, rfl⟩
|
|
| whileTR Dc' _ _ =>
|
|
have ⟨hb, _⟩ := ihc Dc'
|
|
injection hb with hb_eq
|
|
exact Bool.noConfusion hb_eq
|
|
| whileTR _ _ _ ihc ihb ihw =>
|
|
cases D₂ with
|
|
| whileFR Dc' =>
|
|
have ⟨hb, _⟩ := ihc Dc'
|
|
injection hb with hb_eq
|
|
exact Bool.noConfusion hb_eq
|
|
| whileTR Dc' Db' Dw' =>
|
|
have ⟨_, hE1⟩ := ihc Dc'; subst hE1
|
|
have ⟨_, hE2⟩ := ihb Db'; subst hE2
|
|
exact ihw Dw'
|
|
|
|
end OctiveLean.Core
|