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


Check True.
Check (True : Set).
Check (True : Type).
Check nat.
Check (nat : Type).
(*
Check (nat : Prop).
*)
Check (Type : Type).


Definition two : nat :=
  S (S O).
Print two.

Definition two' : nat.
apply S.
apply S.
apply O.
Defined.
Print two'.

Lemma eq_two : two = two'.
unfold two, two'.
reflexivity.
Qed.


Check nat.
Check O.
Check S.
Check nat_ind.
Check nat_sind.
Check nat_rec.
Check nat_rect.

Print nat.
Print O.
Print S.
Print nat_ind.
Print nat_rect.


(*
Definition add :=
  fix add (n m : nat)
      : nat :=
    match n with
    | O => m
    | S n' => S (add n' m)
    end.
*)

Fixpoint add (n m : nat) : nat :=
  match n with
  | O => m
  | S n' => S (add n' m)
  end.
Print add.

Lemma add_1_1 :
  add (S O) (S O) = S (S O).
(*
cbv delta. cbv iota.
cbv beta. cbv iota.
cbv beta. cbv iota.
cbv beta. cbv iota.
*)
(*
compute.
vm_compute.
native_compute.
unfold add.
auto.
*)
simpl.
reflexivity.
Qed.

Eval compute in
  add (S O) (S O).


Lemma add_O_n (n : nat) :
  add O n = n.
reflexivity.
Qed.

Lemma add_n_O (n : nat) :
  add n O = n.
induction n as [|n' IH].
- reflexivity.
- simpl. rewrite IH.
  reflexivity.
Qed.

Definition add' (n m : nat)
    : nat.
(*
destruct n as [|n'].
- apply m.
- 
*)
induction n as [|n' r].
- apply m.
- apply S. apply r.
Defined.
Print add'.

Definition add'' (n m : nat)
    : nat :=
  nat_rec (fun _ => nat) m (fun n' r => S r) n.


Inductive pnat : Prop :=
| pO : pnat
| pS : pnat -> pnat.

Check nat_rec.
Check pnat_ind.


Print unit.
Print True.

Print Empty_set.
Print False.

Print prod.
Print and.

Print sum.
Print or.
Print sumbool.

Print sigT.
Print sig.
Print ex.


Check sum_rec.
Check or_ind.


Check Prop.
Check True.
Check False.
Check I.
Check bool.
Check true.
Check false.

Print True.
Print False.
Print bool.
Print true.
Print false.


Inductive blist : Set :=
| bnil : blist
| bcons : bool -> blist -> blist.

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


Inductive vec (A : Set) : nat -> Set :=
| vnil : vec A O
| vcons : forall n : nat, A -> vec A n -> vec A (S n).

(*
Fixpoint vappend (A : Set) (n m : nat)
    (v : vec A n) (w : vec A m) : vec A (add n m) :=
  match v in vec _ n return vec A (add n m) with
  | vnil _ => w
  | vcons _ n' h t => vcons A (add n' m) h (vappend A n' m t w)
  end.
*)

Arguments vcons {A} {n}.

Fixpoint vappend {A : Set} {n m : nat}
    (v : vec A n) (w : vec A m) : vec A (add n m) :=
  match v in vec _ n return vec A (add n m) with
  | vnil _ => w
  | vcons h t => vcons h (vappend t w)
  end.


Inductive bintree : Set :=
| node : bintree -> bintree -> bintree
| leaf : bintree.

Check node (node leaf leaf) leaf.

Inductive W (A : Set) (B : A -> Set) : Set :=
| sup : forall x : A, (B x -> W A B) -> W A B.

Check W_rec.

Check let A := bool : Set in
  let B := (fun x : bool => if x then bool else Empty_set) : A -> Set in
  let node l r := (sup A B true (fun x => if x then l else r)) : W A B in
  let leaf := (sup A B false (Empty_set_rec (fun _ => W A B))) : W A B in
  node (node leaf leaf) leaf.


Inductive even
    : nat -> Prop :=
| even_O : even O
| even_SS n :
    even n ->
    even (S (S n)).

(*
Inductive le : nat -> nat -> Prop :=
| le_n : forall n : nat, le n n
| le_S : forall n m : nat, le n m -> le n (S m).
*)

Inductive le (n : nat) : nat -> Prop :=
| le_n : le n n
| le_S : forall m : nat, le n m -> le n (S m).


Lemma even_4 :
  even (S (S (S (S O)))).
apply even_SS.
apply even_SS.
apply even_O.
Qed.

Print even_4.


Ltac my_inversion H :=
  inversion H; clear H; subst.

Lemma odd_3 :
  ~ even (S (S (S O))).
intro H.
(*
induction H.
inversion H.
simple inversion H.
inversion_clear H.
inversion H; subst.
inversion H; clear H; subst.
*)
my_inversion H.
my_inversion H1.
Qed.


Check nat_ind.
Check even_ind.


Inductive eq_nat (n : nat) : nat -> Prop :=
| eq_n : eq_nat n n.

(*
Inductive eq (A : Type) : A -> A -> Prop :=
| eq_refl : forall x : A, eq A x x.

Check eq_ind.
*)

Print eq.
Check eq_ind.
