(** To define the type of natural numbers, we introduce an extra
    universe Typ0 *below* the universe Typ1 (so that we are now
    working in the PTS lambda-omega.3).

    Another possibility would be to consider an axiomatized type
    of natural numbers (as in the author's LICS submission). *)

Definition Typ0 : Typ1 := Type.(*******************************************)
(** * The type of Church numerals in Typ1  *)
(*******************************************)

(** ** Definition of natural numbers **)

(** Notice that the following definition is *predicative*, and the
    dependent product ranging over all X:Typ0 builds a type in the
    next universe Typ1.  In practice, this "predicativisation" of
    the type of natural numbers induces some minor changes in the
    implementation of the predecessor function. *)

Definition nat : Typ1 := forall X : Typ0, X -> (X -> X) -> X.Definition O : nat := fun X x f => x.Definition S (n : nat) : nat := fun X x f => f (n X x f).(** A natural number is `well-formed' if it is in the smallest class
    containing zero and closed under the successor function. *)

Definition wf_nat (n : nat) : Prop :=
  forall P : nat -> Prop, P O -> (forall p : nat, P p -> P (S p)) -> P n.(** ** The predecessor function **)

(** For any type X : Typ0, we define the pseudo-square (sqr X) : Typ0
    and the constructor (pair X) : X->X->(sqr X) by setting: *)

Definition sqr (X : Typ0) : Typ0 := (X -> X -> X) -> X.Definition pair (X : Typ0) (x y : X) : sqr X := fun f => f x y.(** The corresponding projections *)

Definition fst (X : Typ0) (p : sqr X) : X := p (fun x _ => x).Definition snd (X : Typ0) (p : sqr X) : X := p (fun _ y => y).(** enjoy the expected definitional equalities:

    (fst X (pair X x y)) = x   and   (snd X (pair X x y)) = y. *)

(** Now, consider an arbitrary function f : X->X.  From this function, we
    define a function  (step X f) : (sqr X)->(sqr X)  that maps the pair
    (x, y) to the pair (y, (f y)) by setting: *)

Definition step (X : Typ0) (f : X -> X) (p : sqr X) : 
  sqr X := pair X (snd X p) (f (snd X p)).(** If we iterate the function (step X f) from an arbitrary pair of the
    form (x, x), we obtain

    (step X f)^0 (x, x) = (x, x)
    (step X f)^1 (x, x) = (x, (f x))
    (step X f)^2 (x, x) = ((f x), (f (f x))
    ...
    (step X f)^n (x, x) = ((f ... (f x) ...), (f ... (f x) ...))
                            ^^^^^^^^           ^^^^^^^^
                            n-1 times          n times

    By extracting the first component of the result and abstracting it
    w.r.t. the variables X:Typ0, x:X and f:X->X, we thus obtain the
    predecessor of Church numeral n.  This is how the predecessor
    function is implemented: *)

Definition pred (n : nat) : nat :=
  fun X x f => fst X (n (sqr X) (pair X x x) (step X f)).

(* Specifications: *)
Lemma pred_O : eq nat (pred O) O.
Lemma pred_SO : eq nat (pred (S O)) O.
Lemma pred_SSn : forall n : nat, eq nat (pred (S (S n))) (S (pred (S n))).
Lemma pred_S : forall n : nat, wf_nat n -> eq nat (pred (S n)) n.
Lemma wf_nat_O : wf_nat O.
Lemma wf_nat_S : forall n : nat, wf_nat n -> wf_nat (S n).
Lemma eq_S_O : forall n : nat, wf_nat n -> eq nat (S n) O -> bot.
Lemma eq_O_S : forall n : nat, wf_nat n -> eq nat O (S n) -> bot.
Lemma eq_S_S : forall n : nat, wf_nat n -> forall p : nat, wf_nat p -> eq nat (S n) (S p) -> eq nat n p.
Lemma nat_ind : forall P : nat -> Prop, P O -> (forall p : nat, wf_nat p -> P p -> P (S p)) -> forall n : nat, wf_nat n -> P n.
Lemma nat_ind' : forall n : nat, wf_nat n -> forall P : nat -> Prop, P O -> (forall p : nat, wf_nat p -> P p -> P (S p)) -> P n.