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

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

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

Print add_n_O.


Lemma seven
    (a : Prop) :
  (forall b : Prop,
    b) -> a.
intros x.
apply x.
Qed.

Print seven.


Lemma eight (a : Prop) :
  (exists b : Prop, a) <-> a.
split.
- intros [b y]. apply y.
- intros z. exists True. apply z.
Qed.

Print eight.


Inductive even_ : nat -> Set :=
| even__O : even_ O
| even__SS n : even_ n -> even_ (S (S n)).

Check even__ind.

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

Check even_ind.


Lemma odd_3 : ~ even (S (S (S O))).
intro H.
(*
inversion H.
inversion_clear H.
inversion H; clear H; subst.
simple inversion H.
Focus 2.
*)
apply (even_ind (fun n => n = S (S (S O)) -> False)) with
  (n := S (S (S O))).
- intro H1. discriminate H1.
- intros n H1 _ H2. injection H2. intros H3. subst.
  inversion H1.
- apply H.
- reflexivity.
Qed.


Definition is_S n :=
  match n with S _ => True | _ => False end.

Definition discriminate_S_O n :
    ~(S n = O) :=
  eq_ind (S n) is_S I O.

Definition S_inv n :=
  match n with S m => m | _ => O end.

Definition injection_S n m :
    S n = S m -> n = m :=
  eq_ind (S n) (fun z => n = S_inv z)
    (eq_refl n) (S m).


(*
Parameter A : Set.
Parameter p : A -> A -> A -> Prop.

Lemma pattern_example x y : x = y -> p x x x.
intros H.
pattern x at 1 3.
rewrite H.
*)


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

Definition lt n m := le (S n) m.

Lemma le_n_S (n m : nat) : le (S n) (S m) -> le n m.
revert n; induction m as [|m' IH]; intros n H;
  inversion H as [|n' H1]; clear H; subst.
- apply le_n.
- inversion H1.
- apply le_n.
- apply le_S. apply IH. apply H1.
Qed.

Lemma lt_irrefl (n : nat) : ~ lt n n.
induction n as [|n' IH].
- intro H. inversion H.
- intro H. apply IH. apply le_n_S. apply H.
Qed.

(*
Require Import Arith.
*)

Definition pred (n : nat) : lt O n -> {m : nat | n = S m}.
intro H. destruct n as [|m].
- elim (lt_irrefl O H).
- exists m. reflexivity.
Defined.

Check (@sig nat (fun m : nat => O = S m)).

Check pred.
Print pred.

Require Extraction.
Extraction pred.
Recursive Extraction pred.


(*
Parameter A B C : Prop.
Lemma or_implies (H : A \/ B) : C.
elim H.
Focus 2.

Parameter P : nat -> Prop.
Lemma forall_nat (n : nat) : P n.
induction n.
Focus 2.
Show Proof.
*)

Print nat_ind.


Inductive pbool : Prop :=
| ptrue : pbool
| pfalse : pbool.

Check (forall a : Set, a -> bool).
Check (forall a : Prop, a -> pbool).

Definition pnot (b : pbool) : pbool :=
  match b with
  | ptrue => pfalse
  | pfalse => ptrue
  end.

(* "classical" axioms *)
Axiom EM : forall a : Prop, a \/ ~a.
Axiom PI_eq : forall (a : Type) (x : a) (H : x = x), H = eq_refl.

Definition X := (forall a : Prop, a -> pbool) : Prop.

Definition f : X.
intros a x.
destruct (EM (a = X)) as [H|H].
- rewrite H in x.
  apply pnot. apply (x X x).
- apply ptrue.
Defined.

Lemma paradox : f X f = pnot (f X f).
unfold f at 1. destruct (EM (X = X)) as [H|H].
- apply f_equal.
  rewrite (PI_eq Prop X H). simpl. reflexivity.
- destruct H. reflexivity.
Qed.

Lemma pbool_degenerate : ptrue = pfalse.
assert (H : forall b, b = f X f -> pnot b = b).
- intros; subst. pattern (f X f) at 2. rewrite paradox. reflexivity.
- destruct (f X f).
  + change (ptrue = pnot ptrue). rewrite H; reflexivity.
  + change (pnot pfalse = pfalse). rewrite H; reflexivity.
Qed.
