(** This shows why the inductive definition of [and] can be manipulated by tactics as we've been doing.  We can also use it to build proofs directly, using pattern-matching.  For instance: *)
Definition and_comm' P Q : P /\ Q <-> Q /\ P :=
conj (and_comm'_aux P Q) (and_comm'_aux Q P).
(** **** Exercise: 2 stars, optional (conj_fact)  *)
(** Construct a proof object demonstrating the following proposition. *)
Definition conj_fact : forall P Q R, P /\ Q -> Q /\ R -> P /\ R
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted. (** [] *)
(** ** Disjunction  The inductive definition of disjunction uses two constructors, one for each side of the disjunct: *)
Module Or.
Inductive or (P Q : Prop) : Prop :=
| or_introl : P -> or P Q
| or_intror : Q -> or P Q.
End Or.
(** This declaration explains the behavior of the [destruct] tactic on a disjunctive hypothesis, since the generated subgoals match the shape of the [or_introl] and [or_intror] constructors.  Once again, we can also directly write proof objects for theorems involving [or], without resorting to tactics. *)
(** **** Exercise: 2 stars, optional (or_commut'')  *)
(** Try to write down an explicit proof object for [or_commut] (without using [Print] to peek at the ones we already defined!). *)
Definition or_comm : forall P Q, P \/ Q -> Q \/ P
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted. (** [] *)
(** ** Existential Quantification  To give evidence for an existential quantifier, we package a witness [x] together with a proof that [x] satisfies the property [P]: *)
Module Ex.
Inductive ex {A : Type} (P : A -> Prop) : Prop :=
| ex_intro : forall x : A, P x -> ex P.
End Ex.
(** This may benefit from a little unpacking.  The core definition is for a type former [ex] that can be used to build propositions of the form [ex P], where [P] itself is a _function_ from witness values in the type [A] to propositions.  The [ex_intro] constructor then offers a way of constructing evidence for [ex P], given a witness [x] and a proof of [P x].  The more familiar form [exists x, P x] desugars to an expression involving [ex]: *)
Check ex (fun n => ev n).
(* ===> exists n : nat, ev n : Prop *)
(** Here's how to define an explicit proof object involving [ex]: *)
Definition some_nat_is_even : exists n, ev n :=
ex_intro ev 4 (ev_SS 2 (ev_SS 0 ev_0)).
(** **** Exercise: 2 stars, optional (ex_ev_Sn)  *)
(** Complete the definition of the following proof object: *)
Definition ex_ev_Sn : ex (fun n => ev (S n))
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted. (** [] *)
(* ================================================================= *)
(** ** [True] and [False] *)
(** The inductive definition of the [True] proposition is simple: *)
Inductive True : Prop :=
| I : True.
(** It has one constructor (so every proof of [True] is the same, so being given a proof of [True] is not informative.) *)
(** [False] is equally simple -- indeed, so simple it may look syntactically wrong at first glance! *)
Inductive False : Prop :=.
(** That is, [False] is an inductive type with _no_ constructors -- i.e., no way to build evidence for it. *)
End Props.
(* ################################################################# *)
(** * Equality *)
(** Even Coq's equality relation is not built in.  It has the following inductive definition.  (Actually, the definition in the standard library is a small variant of this, which gives an induction principle that is slightly easier to use.) *)
Module MyEquality.
Inductive eq {X:Type} : X -> X -> Prop :=
| eq_refl : forall x, eq x x.
Notation "x = y" := (eq x y)
(at level 70, no associativity)
: type_scope.
(** The way to think about this definition is that, given a set [X], it defines a _family_ of propositions "[x] is equal to [y]," indexed by pairs of values ([x] and [y]) from [X].  There is just one way of constructing evidence for each member of this family: applying the constructor [eq_refl] to a type [X] and a value [x : X] yields evidence that [x] is equal to [x]. *)
(** **** Exercise: 2 stars (leibniz_equality)  *)
(** The inductive definition of equality corresponds to _Leibniz equality_: what we mean when we say "[x] and [y] are equal" is that every property on [P] that is true of [x] is also true of [y].  *)

(* Specifications: *)
Lemma leibniz_equality : forall (X : Type) (x y: X),
x = y -> forall P:X->Prop, P x -> P y.