Properties

module stlc.prop where

We show a few basic lemmas related to typing and reduction here.

Imports

open import stlc.base
open multistep

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (; zero; suc)
open import Data.Fin using (Fin; zero; suc)
open import Data.Product using (_×_; _,_; ∃-syntax; Σ-syntax)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_; contradiction)
open import Data.Empty using (; ⊥-elim)

Some Useful Lemmas

Before we can prove progress and preservation, we need to first show that renaming and substitution preserves typing.

The lemma ty-rename basically states that: given a term M with type A under context Γ, and a renaming function ρ that maps all variables from context Γ to Δ while preserving their types, the renamed term is still typed A under the new context Δ.

ty-ext :  {n A} {Γ : Context n}
    {m ρ} {Δ : Context m}  (∀ {x B}  Γ  x  B  Δ  ρ x  B)
    --------------------------------------------------------------
    {x B}  Γ ,- A  x  B  Δ ,- A  ext ρ x  B
ty-ext ⊢ρ Z     = Z
ty-ext ⊢ρ (S x) = S (⊢ρ x)

ty-rename :  {n M A} {Γ : Context n}
   Γ  M  A
    {m ρ} {Δ : Context m}  (∀ {x B}  Γ  x  B  Δ  ρ x  B)
    --------------------------------------------------------------
   Δ  rename ρ M  A
ty-rename (⊢var x)       ⊢ρ = ⊢var (⊢ρ x)
ty-rename (⊢abs ⊢M)      ⊢ρ = ⊢abs (ty-rename ⊢M (ty-ext ⊢ρ))
ty-rename (⊢app ⊢M ⊢N)   ⊢ρ = ⊢app (ty-rename ⊢M ⊢ρ) (ty-rename ⊢N ⊢ρ)
ty-rename ⊢true          ⊢ρ = ⊢true
ty-rename ⊢false         ⊢ρ = ⊢false
ty-rename (⊢if ⊢L ⊢M ⊢N) ⊢ρ = ⊢if (ty-rename ⊢L ⊢ρ) (ty-rename ⊢M ⊢ρ) (ty-rename ⊢N ⊢ρ)

Similarly, for substitution:

ty-exts :  {n A} {Γ : Context n}
    {m σ} {Δ : Context m}  (∀ {x B}  Γ  x  B  Δ  σ x  B)
    --------------------------------------------------------------
    {x B }  Γ ,- A  x  B  Δ ,- A  exts σ x  B
ty-exts ⊢σ Z     = ⊢var Z
ty-exts ⊢σ (S x) = ty-rename (⊢σ x) S

ty-subst :  {n M A} {Γ : Context n}
   Γ  M  A
    {m σ} {Δ : Context m}  (∀ {x B}  Γ  x  B  Δ  σ x  B)
    --------------------------------------------------------------
   Δ  subst σ M  A
ty-subst (⊢var x)       ⊢σ = ⊢σ x
ty-subst (⊢abs ⊢M)      ⊢σ = ⊢abs (ty-subst ⊢M (ty-exts ⊢σ))
ty-subst (⊢app ⊢M ⊢N)   ⊢σ = ⊢app (ty-subst ⊢M ⊢σ) (ty-subst ⊢N ⊢σ)
ty-subst ⊢true          ⊢σ = ⊢true
ty-subst ⊢false         ⊢σ = ⊢false
ty-subst (⊢if ⊢L ⊢M ⊢N) ⊢σ = ⊢if (ty-subst ⊢L ⊢σ) (ty-subst ⊢M ⊢σ) (ty-subst ⊢N ⊢σ)

Main Lemmas

Preservation: small step reduction (of a closed term) preserves typing. It proceeds by induction on the typing judgement and the reduction.

Note that we need to use the lemma ty-subst for the beta rules β-abs to show that typing is preserved in single substitution.

preservation :  {M M' A}
     M  A
   M —→ M'
    -----------
     M'  A
preservation (⊢app ⊢M ⊢N)        (ξ-app₁ M→M') = ⊢app (preservation ⊢M M→M') ⊢N
preservation (⊢app ⊢M ⊢N)        (ξ-app₂ N→N') = ⊢app ⊢M (preservation ⊢N N→N')
preservation (⊢app (⊢abs ⊢M) ⊢N) (β-abs VN)    = ty-subst ⊢M  { Z  ⊢N })
preservation (⊢if ⊢L ⊢M ⊢N)      (ξ-if L→L')   = ⊢if (preservation ⊢L L→L') ⊢M ⊢N
preservation (⊢if ⊢L ⊢M ⊢N)      β-if₁         = ⊢M
preservation (⊢if ⊢L ⊢M ⊢N)      β-if₂         = ⊢N

Progress: a well typed term can either take a step or it is a value. It proceeds on the induction of the typing judgement.

data Progress {n} : Term n  Set where

  step :  {M N : Term n}
     M —→ N
      -----------
     Progress M

  done :  {M : Term n}
     Value M
      -----------
     Progress M

progress :  {M A}
     M  A
    -----------
   Progress M
progress (⊢abs ⊢M)                       = done V-abs
progress (⊢app ⊢M ⊢N) with progress ⊢M
... | step M—→M'                         = step (ξ-app₁ M—→M')
... | done V-abs with progress ⊢N
...   | step N—→N'                       = step (ξ-app₂ N—→N')
...   | done VN                          = step (β-abs VN)
progress ⊢true                           = done V-true
progress ⊢false                          = done V-false
progress (⊢if ⊢L ⊢M ⊢N) with progress ⊢L
... | step L—→L'                         = step (ξ-if L—→L')
... | done V-true                        = step β-if₁
... | done V-false                       = step β-if₂

A value of type Bool is either true or false.

Canonical-Bool :  {n M} {Γ : Context n}
   Γ  M  Bool
   Value M
    ---------------------
   M  true  M  false
Canonical-Bool ⊢true  V-true  = inj₁ refl
Canonical-Bool ⊢false V-false = inj₂ refl

A value of the function type is a lambda abstraction.

Canonical-⇒ :  {n M A B} {Γ : Context n}
   Γ  M  A  B
   Value M
    ---------------
   ∃[ N ] M  ƛ N
Canonical-⇒ {M = ƛ N} (⊢abs ⊢N) V-abs = N , refl

Value does not step.

V-¬—→ :  {n} {M N : Term n}
   Value M
    -----------
   ¬ (M —→ N)
V-¬—→ V-abs   ()
V-¬—→ V-true  ()
V-¬—→ V-false ()

Small step reduction is deterministic.

—→-determ :  {n} {M N N' : Term n}
   M —→ N  M —→ N'
    -----------------
   N  N'
—→-determ (ξ-app₁ M→N) (ξ-app₁ M→N') rewrite —→-determ M→N M→N' = refl
—→-determ (ξ-app₁ M→N) (ξ-app₂ M→N') = ⊥-elim (V-¬—→ V-abs M→N)
—→-determ (ξ-app₂ M→N) (ξ-app₁ M→N') = ⊥-elim (V-¬—→ V-abs M→N')
—→-determ (ξ-app₂ M→N) (ξ-app₂ M→N') rewrite —→-determ M→N M→N' = refl
—→-determ (ξ-app₂ M→N) (β-abs V')    = ⊥-elim (V-¬—→ V' M→N)
—→-determ (β-abs V)    (ξ-app₂ M→N') = ⊥-elim (V-¬—→ V M→N')
—→-determ (β-abs V)    (β-abs V')    = refl
—→-determ (ξ-if M→N)   (ξ-if M→N')   rewrite —→-determ M→N M→N' = refl
—→-determ β-if₁        β-if₁         = refl
—→-determ β-if₂        β-if₂         = refl

Lemmas for Multi-step

Multi-step is transitive.

—→*-trans :  {n} {L M N : Term n}
   L —→* M  M —→* N
    ------------------
   L —→* N
—→*-trans (L )                  M—→*N = M—→*N
—→*-trans (L —→⟨ L—→L'  L'—→*M) M—→*N = L —→⟨ L—→L'  —→*-trans L'—→*M M—→*N

Multi-step preserves typing.

—→*-pres :  {A M M'}    M  A  M —→* M'    M'  A
—→*-pres ⊢M (M )                  = ⊢M
—→*-pres ⊢M (M —→⟨ M—→M'  M'—→*N) = —→*-pres (preservation ⊢M M—→M') M'—→*N

Determinism implies confluence.

confluence :  {n} {L M M' : Term n}
   L —→* M  L —→* M'
    ------------------------------
   ∃[ N ] (M —→* N) × (M' —→* N)
confluence (_ )                L—→*M'                = _ , L—→*M' , (_ )
confluence (_ —→⟨ L→L₁  L₁→*M) (_ )                 = _ , (_ ) , (_ —→⟨ L→L₁  L₁→*M)
confluence (_ —→⟨ L→L₁  L₁→*M) (_ —→⟨ L→L₂  L₂→*M') rewrite —→-determ L→L₁ L→L₂ = confluence L₁→*M L₂→*M'

A few congruence lemmas:

appL-cong :  {n} {M M' N : Term n}
   M —→* M'
    -----------------
   M · N —→* M' · N
appL-cong (_ )                   = _ 
appL-cong (_ —→⟨ M—→M₁  M₁—→*M') = _ —→⟨ ξ-app₁ M—→M₁  appL-cong M₁—→*M'

appR-cong :  {n M} {N N' : Term n}
   N —→* N'
    -------------------------
   (ƛ M) · N —→* (ƛ M) · N'
appR-cong (_ )                   = _ 
appR-cong (_ —→⟨ N—→N₁  N₁—→*N') = _ —→⟨ ξ-app₂ N—→N₁  appR-cong N₁—→*N'

if-cong :  {n} {L L' M N : Term n}
   L —→* L'
    -----------------------
   if L M N —→* if L' M N
if-cong (_ )                   = _ 
if-cong (_ —→⟨ L—→L₁  L₁—→*L') = _ —→⟨ ξ-if L—→L₁  (if-cong L₁—→*L')