You know how basic theorems about lambda calculus can be formalized using a proof assistant
This is an extra chapter about formalization of programming language theory.
We are going to prove and formalize type safety for the simply typed lambda calculus from chapter 5.
Firstly, what is formalization?
Formalization is the process of converting something informal to something formal.
Mathematics can be formalized by e.g. using programming languages.
Some programming languages such as Lean are built with mathematics in mind and a significant amount of mathematics has already been formalized in Lean.
All of the code presented here is found in lean playground1 (click the footnote to open it).
While reading the material, move your cursor along in the editor to see how Leanβs InfoView changes.
Type Safety
Type safety in programming languages consists of two parts:
Preservation: Types are preserved during evaluation.
If and , then .
This can be written more formally as
Progress: Well-typed terms are values or can be reduced.
If , then either is a value, or there exists
This can be written more formally as
The rules we have given actually guarantee a stronger property than progress: unicity.
This means that there is a unique term to reduce to:
Read more in chapter 6 of Practical Foundations for Programming Languages.
Definitions
First, the definitions of terms and types are the following two inductive types
/-
# Definition 6.5.1: Terms and Types of STLC + π
An inductive proposition is an inductive data type, but in the universe of propositions.
Like other algebraic data types, inductive propositions can be constructed with its constructors and deconstructed by case matching.
inductiveValue : Term β Propwhere
| Abs : β {x} {T} {t}, Value (.Abs x T t)
| False : Value False
| True : Value True
example : Value False := Value.False
example : Value (Abs "x" .Boolean (Var "x")) :=
@Value.Abs "x" .Boolean (Var "x")
Because the arguments to Abs are implicit, Lean can infer them in some situations.
Therefore we can shorten the proof for abstraction example to:
example : Value (Abs "x" .Boolean (Var "x")) := Value.Abs
Finally to case analyze some Value t, we can use the cases tactic.
For example, the following proof shows that a value is either False, True or there exist x, T, tβ such that the value is Abs x T tβ.
example (h : Value t) : t = False β¨ t = True β¨ β x T tβ, t = Abs x T tβ := by
cases h with
| True =>
-- β’ True = False β¨ True = True β¨ β x T tβ, True = Abs x T tβ
-- Which holds as the middle disjunct is true
right
left
rfl
| False =>
-- β’ False = False β¨ False = True β¨ β x T tβ, False = Abs x T tβ
left
rfl
| @Abs y U t =>
/-
y : String
U : Ty
t : Term
β’ Abs y U t = False β¨ Abs y U t = True β¨ β x T tβ, Abs y U t = Abs x T tβ
-/
-- This is true because we can use `x = y` `T = U` and `tβ = t` to prove the β
Now that we have defined the Context, letβs move on to typing next.
First, a quick reminder β the typing rules for the core of STLC:
The hypothetical typing judgement (Definition 6.5.4) is the following inductive trinary relation:
/--
# Definition 6.5.4: Hypothetical Typing Judgment
-/
inductiveHasType : Context β Term β Ty β Propwhere
| Var : β Ξ x T,
T β Ξ x β
-------------------
HasType Ξ (Var x) T
| Abs : β Ξ x Tβ Tβ tβ,
HasType (Ξ.update x Tβ) tβ Tβ β
--------------------------------------
HasType Ξ (Abs x Tβ tβ) (.Arrow Tβ Tβ)
| App : β Ξ tβ tβ T Tβ,
HasType Ξ tβ (.Arrow Tβ T) β
HasType Ξ tβ Tβ β
-----------------------
HasType Ξ (App tβ tβ) T
-- Booleans
| True : HasType Ξ True .Boolean
| False : HasType Ξ False .Boolean
| Ite :
HasType Ξ tβ .Boolean β
HasType Ξ tβ T β
HasType Ξ tβ T β
-------------------------
HasType Ξ (Ite tβ tβ tβ) T
Plus notation:
notation:50 Ξ:51" β’ " t:52" β· " T => HasType Ξ t T
Examples from Example 6.5.5:
/-
# Example 6.5.5
-/
example : "x" β· .Boolean β’ (Var "x") β· .Boolean := by
apply HasType.Var
exact Context.mem_update
example : β β’ (Abs "x" .Boolean (Var "x")) β· .Arrow .Boolean .Boolean := by
apply HasType.Abs
apply HasType.Var
exact Context.mem_update
Next, letβs actually prove some properties about !
Canonical terms
The canonical terms lemmas state that a value of Arrow type must be an abstraction, and a value of Boolean type must be either True or False
The lemmas are useful when proving the progress theorem.
lemmacanonical_abs {t Tβ Tβ} (h : β β’ t β· .Arrow Tβ Tβ) (ht : Value t) : β x tβ, t = Abs x Tβ tβ := by
cases ht with
| @Abs x T tβ =>
cases h
use x
use tβ
| True | False =>
nomatch h
lemmacanonical_bool {t} (h : β β’ t β· .Boolean) (ht : Value t) : t = True β¨ t = False := by
cases ht with
| @Abs x T tβ =>
cases h
| True | False =>
tauto
Progress Theorem
/-
# Theorem: Progress
-/
theoremprogress {t} {T} (h : β β’ t β· T) : Value t β¨ β t', t βΆ t'
The progress theorem states that all well-typed terms (in the empty context) are either values, or can be reduced further.
This means that itβs not possible for a term to be βstuckβ so that itβs neither.
This is one of the two requirements for type safety.
See theorem progress for the proof details in the Lean environment1.
Preservation Theorem
/-
# Theorem: Preservation
-/
theorempreservation {t t'} {T} (h : β β’ t β· T) (ht : t βΆ t') : β β’ t' β· T
The preservation theorem states that a well-typed termβs type is preserved during -reduction.
This theorem is easy to prove with the help of a few lemmas called weakening and substitution:
/-
# Lemma: Weakening
-/
lemmaweakening {Ξ Ξ'} {t} {T} (hg : Ξ β Ξ') (h : Ξ β’ t β· T) : Ξ' β’ t β· T := by
/-
# Lemma: Substitution
-/
lemmasubstitution {Ξ} {x} {v t} {U T} (ht : Ξ.update x U β’ t β· T) (h : β β’ v β· U)
: Ξ β’ [x β¦ v] t β· T
See theorem preservation for the proof details in the Lean environment1.
With both preservation and progress, we know that is type safe.
STLC Extensions
Itβs not too difficult to extend type safety (i.e. progress and preservation theorems) to STLC with extensions.
Hereβs the definition of a language based on STLC with unit types, booleans, integers, lists, pairs, sums, fixed point combinator and let-expressions.
/- Omitted other definitions about Context, Value, subst etc. -/
theoremprogress {t} {T} (h : β β’ t β· T) : Value t β¨ β t', t βΆ t' := sorry
theorempreservation {t t'} {T} (h : β β’ t β· T) (ht : t βΆ t') : β β’ t' β· T := sorry
As a final exercise to the reader, formally prove the preservation and progress theorems for this language.
However, no points are awarded for completing this exercise.