Inductive Types Explained from First Principles


We try to explain inductive types from a foundational point of view not using match and fix. Suppose we define

Inductive bool := false | true.

As a result the environment is extended with 4 typings and 2 computation rules are added:
bool : Set
false : bool
true : bool
bool_rect : forall p : bool -> Type, p false -> p true -> forall x : bool, p x

bool_rect t t1 t1 false ---> t1
bool_rect t t1 t2 true  ---> t2


That's it. The key properties of the underlying calculus of constructions are preserved by this extension (e.g., type preservation, termination, consistency).

The following definitions suggest that bool_rect gives us all we need.

Definition bool_Ind : forall p : bool -> Prop, p false -> p true -> forall x : bool, p x
:=fun p => bool_rect (fun x => p x).

Definition bool_case : forall Z : Type, Z -> Z -> bool ->Z
:= fun Z => bool_rect (fun _ => Z).

Eval compute in bool_case nat 7 9 false.
Eval compute in bool_case nat 7 9 true.

With bool_case one can prove that the constructors false and true are different, something one cannot do for the Church-Girard encoding of bool. We do the proof just using first principles.

Definition False : Prop := forall X:Prop, X.
Definition True : Prop := forall X:Prop, X -> X.
Definition I : True := fun X x => x.
Definition eq (X:Type) (x y : X) : Prop := forall p : X -> Prop, p x -> p y.

Definition false_neq_true : eq bool false true -> False :=
fun f => f (bool_case Prop True False) I.

Coq defines bool_rect with dependent match.

Definition bool_Rect : forall p : bool -> Type, p false -> p true -> forall x : bool, p x
:= fun p a b x => match x return p x with false => a | true => b end.

Let's now consider the inductive type of natural numbers.

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

This time we get the following extensions:
int : Set
O : nat
S : nat -> nat
nat_rect : forall p : nat -> Type, p O -> (forall x : nat, p x -> p(S x)) -> forall x : nat, p x

nat_rect t t1 t1 O ---> t1
nat_rect t t1 t2 (S u) ---> t2 u (nat_rect t t1 t2 u)


Once again nat_rect gives us all we need.

Definition nat_Ind : forall p : nat -> Prop, p O -> (forall x : nat, p x -> p(S x)) -> forall x : nat, p x
:= fun p => nat_rect (fun x => p x).

Definition nat_Rec : forall Z : Type, Z -> (nat -> Z -> Z) -> nat -> Z
:= fun Z => nat_rect (fun _ => Z).

Eval compute in nat_Rec nat O (fun _ a => S(S(S a))) (S(S O)).

Definition nat_case : forall Z : Type, Z -> (nat -> Z) -> nat -> Z
:= fun Z a b => nat_Rec Z a (fun x _ => b x).

Definition pred : nat -> nat := nat_case nat O (fun y => y).

Definition O_neq_S : forall n, eq nat O (S n) -> False :=
fun _ f => f (nat_case Prop True (fun _ => False)) I.

Definition S_injective: forall x y, eq nat (S x) (S y) -> eq nat x y
:= fun x _ f => f
( nat_case Prop True (eq nat x))
(fun _ b => b).

Coq defines nat_rect with fix and dependent match.

Definition nat_Rect : forall p : nat -> Type, p O -> (forall x : nat, p x -> p(S x)) -> forall x : nat, p x
:= fun p a b => fix ind x := match x return p x with O => a | S x' => b x' (ind x') end.


This page has been generated by coqdoc