Type soundness #
The System F proof, with units in place of type variables.
The shape is the textbook one: a value typing relation, an environment typing relation defined mutually with it (a closure's type depends on the context its captured environment satisfies), and a preservation theorem by induction on the term with the fuel bound handled by an outer strong induction.
Where units show up #
In exactly two places, and neither is structural.
EnvOkD is the semantic counterpart of the dimension context: the runtime unit
environment must assign each unit variable a unit whose dimension is the one
the static context declared. dimOf_substU then says grounding commutes with
taking dimensions. That is the only genuinely dimensional lemma in the file, and
because units are exponent vectors it is a Fubini argument rather than an
induction: the same simplification Kennedy identifies as the payoff of treating
units as an abelian group rather than as syntax, here strengthened by the
representation being a vector rather than a normal form.
Everything else (that grounding commutes with product, quotient and rational
power, that it composes, that weakening is invisible to it) is discharged in
LambdaS.Syntax by linear algebra.
What is proved #
If evaluation returns a value, that value has the type the checker predicted, at
every type and every scope: closures, unit abstraction and dimension abstraction
included. Totality is not claimed here; a fuel-bounded evaluator cannot have it
without a normalization argument, and none stays ambiguous between ill-typed
and out-of-fuel. LambdaS.Normalization supplies the normalization argument,
and with it the "evaluation succeeds" statement at the whole language.
The dimensional side condition #
The runtime environments respect the static dimension context: every unit variable is bound to a unit of the dimension its binder declared.
This is what a unit environment must satisfy to be a semantic model of Δ, and
HasTy.uapp's premise dimOf Δ σ = d is exactly the syntactic check that
maintains it.
Equations
- LambdaS.EnvOkD Δ η δ = ∀ (i : Fin k), LambdaS.dimOf (LambdaS.DCtx.nil D) (η i) = LambdaS.substU δ (Δ i)
Instances For
Grounding commutes with taking dimensions.
The one dimensional lemma in the development. It holds because dimOf and
substU are both linear maps on exponent vectors, so the content is a change in
summation order rather than an induction over syntax.
Extending both the dimension context and the unit environment preserves the condition, provided the new unit has the declared dimension.
Value and environment typing #
A context grounded through the environments.
Equations
- LambdaS.groundCtx η δ Γ = List.map (LambdaS.Ty.ground η δ) Γ
Instances For
A runtime value has the type the checker predicts, grounded.
- scalar {B D R : Type} [Fintype B] [UnitSys B D] (m : R) (u : UExp B 0) : ValTy (Val.scalar { mag := m, unit := u }) (Ty.Q u)
- vector {B D R : Type} [Fintype B] [UnitSys B D] {xs : List R} {V : Sp B 0} : xs.length = List.length V → ValTy (Val.vector xs V) (Ty.vec V)
- matrix {B D R : Type} [Fintype B] [UnitSys B D] {M : List (List R)} {V W : Sp B 0} : M.length = List.length W → (∀ r ∈ M, r.length = List.length V) → ValTy (Val.matrix M V W) (Ty.lin V W)
- closure {B D R : Type} [Fintype B] [UnitSys B D] {j k : ℕ} {Δ : DCtx D j k} {Γ : Ctx B D j k} {σ τ : Ty B D j k} {b : Tm B D j k} {ρ : List (Val R B D)} {η : UEnv B k} {δ : DEnv D j} {T : Ty B D 0 0} : EnvTy ρ (groundCtx η δ Γ) → EnvOkD Δ η δ → ∀ (a✝ : HasTy Δ (σ :: Γ) b τ), T = Ty.ground η δ (σ.arrow τ) → ValTy (Val.closure σ b ρ η δ) T
- uclos {B D R : Type} [Fintype B] [UnitSys B D] {j k : ℕ} {Δ : DCtx D j k} {Γ : Ctx B D j k} {d : DExp D j} {τ : Ty B D j (k + 1)} {b : Tm B D j (k + 1)} {ρ : List (Val R B D)} {η : UEnv B k} {δ : DEnv D j} {T : Ty B D 0 0} : EnvTy ρ (groundCtx η δ Γ) → EnvOkD Δ η δ → ∀ (a✝ : HasTy (DCtx.cons d Δ) Γ.weaken b τ), T = Ty.ground η δ (Ty.all d τ) → ValTy (Val.uclos d b ρ η δ) T
- dclos {B D R : Type} [Fintype B] [UnitSys B D] {j k : ℕ} {Δ : DCtx D j k} {Γ : Ctx B D j k} {τ : Ty B D (j + 1) k} {b : Tm B D (j + 1) k} {ρ : List (Val R B D)} {η : UEnv B k} {δ : DEnv D j} {T : Ty B D 0 0} : EnvTy ρ (groundCtx η δ Γ) → EnvOkD Δ η δ → ∀ (a✝ : HasTy Δ.weakenDim Γ.weakenDim b τ), T = Ty.ground η δ τ.allDim → ValTy (Val.dclos b ρ η δ) T
Instances For
An environment supplies a well-typed value for every entry of a context.
- nil {B D R : Type} [Fintype B] [UnitSys B D] : EnvTy [] []
- cons {B D R : Type} [Fintype B] [UnitSys B D] {v : Val R B D} {ρ : List (Val R B D)} {Γ : Ctx B D 0 0} {τ : Ty B D 0 0} : ValTy v τ → EnvTy ρ Γ → EnvTy (v :: ρ) (τ :: Γ)
Instances For
Inversion #
A value's shape is determined by its type, which is what discharges the
evaluator's | _ => none branches.
The theorem #
Strong induction on the fuel, then ordinary induction on the term. The fuel induction is needed only where evaluation leaves the term (entering a closure body), and the term induction handles everything else, exactly as in the System F development.