Lecture 2: Martin-Löf’s Type Theory, System F, Calculus of Constructions

Teachers: Bruno Barras & Matthieu Sozeau

Martin-Löf’s Type Theory

Martin Löf’s idea: set apart types and terms, they have distinct judgements:

\[Γ ⊢ A \; type\\ Γ⊢M:A\\ Γ ⊢ A = B \quad \text{only on well-typed terms) }\\ Γ⊢M=N:A\]

(types have a specific judgment) (equality

And then:

  • formation rules (for $∏$)
  • introduction rules (for $λ$)
  • elmination rules (for application)
  • computation rules ($β$-reduction)

Type constructors

  • Logical connectives: e.g. \(\cfrac{Γ⊢A \; type \qquad Γ⊢B \; type} {Γ⊢A×B \; type}\)
  • Universes, …
  • Propositional Equality:

    \[\cfrac{Γ ⊢ a, b:A}{Γ ⊢ a=b \; type}\qquad \cfrac{Γ ⊢ a:A}{Γ ⊢ r(a): a=a}\qquad \cfrac{Γ⊢p : a=b \qquad Γ,x:A⊢C(x) \; type \qquad Γ⊢e:C(a)}{Γ⊢J(p,C,e) : C(b)}\]

System F

Invented by Girard and Reynolds independently (1972/74).

New type former: polymorphism:

\[\underbrace{∀α}_{\text{all possible substitution of a type for } α}. \, τ\] \[\cfrac{Γ⊢M :τ \qquad α \text{ not free in } Γ}{Γ⊢Λα.M :∀α.τ}\qquad \cfrac{Γ⊢M :∀α.τ}{ Γ⊢M τ' :τ[τ'/α]}\]

Why is it useful? Enables us to encode second-order arithmetic: e.g. natural numbers:

\[ℕ \, ≝ \, ∀α.α → (α → α) → α\\ [n] \, ≝ \, λx.λf.f^n x\]

But, limitatiions: cannot encode equality (between numbers, etc…): enables us to construct functions, but not reason on them.

Polymorphism also called impredicativity: allows self-application! May seem frightening (we’re coming close to Russel’s paradox?), but not really: System F is not set-theoretic.

Calculus of Constructions (CC)

Coquand and Huet (1985)

Combines ideas from:

  • Martin Löf’s Type Theory
  • Automath: system invented in the 60’s in which we have been able to prove real (analysis) theorems: the proof assistant “pioneer” (the type theory beneath resembles Martin Löf’s type theory).
  • System F (polymorphism)

There are two sorts: Prop and Type (also denoted by $\ast$/$\square$)

Nothing really new compared to ST $λ$-calulus + dependent product, except that here, we have 4 different products, depending on which sorts we’re considering:

\[\cfrac{Γ⊢A:s_1 \qquad Γ;x:A⊢B:s_2}{Γ⊢Πx:A.B : s_2}\]

for $s_1, s_2 ∈ \lbrace Prop, Type \rbrace$

Example:

\[nat: Prop\\ true: Prop\\ Prop:Type\] \[\cfrac{nat:Prop}{nat → nat: Prop}\\ \, \\ \cfrac{nat:Prop \qquad Prop: Type}{nat → Prop: Type} \qquad \text{(in } F_ω \text{: actually, not necessary in CC)}\\ \, \\ \cfrac{Prop: Type \qquad α: Prop \qquad α → α: Prop}{\underbrace{∀α:}_{\text{syntax-sugar for product}} Prop. α → α: Prop}\\ \, \\ \cfrac{Prop: Type}{Prop → Prop: Type}\]
  • CC extends System F: Functions of higher-order arithmetic Propositional connectives ($∧, ∨, \ldots$)

  • CC extends $λΠ$: Predicate calculus: existential quantifier, equality

  • CC is a higher-order logic: in MLTT, no type of all propositions, but in CC, $\ast$ is the type of all propositions of higher-order logic

$CC_ω$: with a hierarchy of universes ($Type_1, Type_2, \ldots$)

Calculus of Introductive Constructions (CIC)

Extends CC with universes and primitive (co-)inductive types (impredicativity allowed).

Constructive logic: if you have a proof of existence, then you have an algorithm yielding a witness.

Datatypes

Natural numbers, rational numbers, lists, finitely branching trees, … can be encoded in Peano arithmetic (PA). But it’s tedious: one prefers a better-suited principle to construct/handle types.

Inductive sets

Induction: examples:

  • mathematical induction
  • define properties/sets of objects via inference rules
  • structural induction (induction on well-founded trees)

In PA, we can define subsets of $ℕ$ with inference rules: examples:

  • natural numbers:

    \[\cfrac{}{0 ∈ ℕ}\\ \, \\ \cfrac{n ∈ ℕ}{S(n) ∈ ℕ}\]
  • even numbers $2ℕ$:

    \[\cfrac{}{0 ∈ 2ℕ}\\ \, \\ \cfrac{n ∈ 2ℕ}{S(S(n)) ∈ 2ℕ}\]

    Minimality: $P(0)$ and $∀n. P(n) ⇒ P(S(S(n)))$ implies $∀n ∈ 2ℕ.P(n)$

Inductive sets as fixpoints

$ℕ$ is the smallest fixpoint of

\[F \, ≝ \, X ⟼ \{0\} ∪ \{S(n) \; \mid \; n ∈ X\}\]
  • Closure by rules: $F(P) ⊆ P$
  • Minimality: $∀P.F(P)⊆P ⇒ ℕ ⊆ P$

HOWEVER: Infinitely branching trees can’t be defined in PA, but they can be defined as an inductive set.

But we can’t go too far: e.g. we can’t set, to define $V$:

\[\cfrac{x ∈ 𝒫(V)}{C(x) ∈ V}\]

Because the powerset is too big. But we can do it for a family indexed by a fixed type:

\[\cfrac{x∈L \qquad f∈ ℕ → V}{Node(x,f) ∈ V}\]

Recursors are special cases of induction schemes.

Inductive types in Coq

Inductive types: specified by introduction rules (referred to as constructors).

Coq is restrained/closed when it comes to defining new inductive types: contrary to MLTT, you can’t introduce any nex inductive type: Coq checks new inductives and accepts only those which don’t provoke any inconsistency.

Inductive nat : Type :=
| O : nat | S : nat -> nat.

or, shorter:

Inductive nat := O | S (n:nat)

By doing that, you get:

  • a type $Γ ⊢ nat : \, Type$
  • a set of introduction rules/constructors for this type

Pattern-matching: to clarify the type on which one matches (Coq can’t always infer it by itself):

match t as x return A(x) with O => t1 | S n => t2 end

Other examples:

Disjunction:

Inductive or (A:Prop) (B:Prop) : Prop :=
| or_introl : A -> or A B
| or_intror : B -> or A B.

Lists:

Inductive list (A:Type) : Type :=
| nil : list A
| cons : A -> list A -> list A.

Infinitely branching trees:

Inductive tree (A:Type) : Type :=
| Leaf : tree A
| Node : A -> (nat -> tree A) -> tree A.

in which case the recursor is given by:

tree_rect =
fun (A : Type) (P : tree A->Type) (f : P (Leaf A))
 (f0 : forall (a : A) (t : nat -> tree A),
    (forall n:nat, P (t n)) -> P (Node A a t)) =>
fix F (t : tree A) : P t :=
  match t as t0 return (P t0) with
  | Leaf => f
  | Node y t0 => f0 y t0 (fun n : nat => F (t0 n))
  end

The absurd type:

Inductive False : Prop := .

Case analysis vs. Recursor

Recursion scheme is decomposed into two “principles” (comes from ML), separating pattern-matching and recurrence:

  • Case Analysis:

      λP :nat->s,
      λHO : P(O),
      λHS : m : nat,P(S m), λn:nat,
      match n return P(n) with O=>HO |Sm=>HS m
      end
    

    of which type is:

      P :nat->s,
      P(O) ->
      (m : nat,P(S m)) -> n : nat, P(n)
    
  • Recursor:

      λP :nat -> s,
      λHO : P(O),
      λHS : m : nat,P(m) -> P(S m), fixf (n:nat) : P(n) :=
      match n return P(n) with O => HO |Sm => HS m(f m)
      end
    

    of which type is:

      P :nat->s,
      P(O) ->
      (m : nat,P(m) -> P(S m)) -> n : nat, P(n)
    

Leave a comment