(** What is the proof object corresponding to [ev_plus4]?  We're looking for an expression whose _type_ is [forall n, ev n -> ev (4 + n)] -- that is, a _function_ that takes two arguments (one number and a piece of evidence) and returns a piece of evidence! Here it is: *)
(** Recall that [fun n => blah] means "the function that, given [n], yields [blah]," and that Coq treats [4 + n] and [S (S (S (S n)))] as synonyms. Another equivalent way to write this definition is: *)
Definition ev_plus4'' (n : nat) (H : ev n) : ev (4 + n) :=
ev_SS (S (S n)) (ev_SS n H).
Check ev_plus4''.
(* ===> ev_plus4'' : forall n : nat, ev n -> ev (4 + n) *)
(** When we view the proposition being proved by [ev_plus4] as a function type, one aspect of it may seem a little unusual. The second argument's type, [ev n], mentions the _value_ of the first argument, [n].  While such _dependent types_ are not found in conventional programming languages, they can be useful in programming too, as the recent flurry of activity in the functional programming community demonstrates.  Notice that both implication ([->]) and quantification ([forall]) correspond to functions on evidence.  In fact, they are really the same thing: [->] is just a shorthand for a degenerate use of [forall] where there is no dependency, i.e., no need to give a name to the type on the left-hand side of the arrow. *)
(** For example, consider this proposition: *)
Definition ev_plus2 : Prop :=
forall n, forall (E : ev n), ev (n + 2).
(** A proof term inhabiting this proposition would be a function with two arguments: a number [n] and some evidence [E] that [n] is even.  But the name [E] for this evidence is not used in the rest of the statement of [ev_plus2], so it's a bit silly to bother making up a name for it.  We could write it like this instead, using the dummy identifier [_] in place of a real name: *)
Definition ev_plus2' : Prop :=
forall n, forall (_ : ev n), ev (n + 2).
(** Or, equivalently, we can write it in more familiar notation: *)
Definition ev_plus2'' : Prop :=
forall n, ev n -> ev (n + 2).
(** In general, "[P -> Q]" is just syntactic sugar for "[forall (_:P), Q]". *)
(* ################################################################# *)
(** * Programming with Tactics *)
(** If we can build proofs by giving explicit terms rather than executing tactic scripts, you may be wondering whether we can build _programs_ using _tactics_ rather than explicit terms. Naturally, the answer is yes! *)
Definition add1 : nat -> nat.
intro n.
Show Proof.
apply S.
Show Proof.
apply n. Defined.
Print add1.
(* ==> add1 = fun n : nat => S n : nat -> nat *)
Compute add1 2.
(* ==> 3 : nat *)
(** Notice that we terminate the [Definition] with a [.] rather than with [:=] followed by a term.  This tells Coq to enter _proof scripting mode_ to build an object of type [nat -> nat].  Also, we terminate the proof with [Defined] rather than [Qed]; this makes the definition _transparent_ so that it can be used in computation like a normally-defined function.  ([Qed]-defined objects are opaque during computation.)  This feature is mainly useful for writing functions with dependent types, which we won't explore much further in this book.  But it does illustrate the uniformity and orthogonality of the basic ideas in Coq. *)
(* ################################################################# *)
(** * Logical Connectives as Inductive Types *)
(** Inductive definitions are powerful enough to express most of the connectives and quantifiers we have seen so far.  Indeed, only universal quantification (and thus implication) is built into Coq; all the others are defined inductively.  We'll see these definitions in this section. *)
Module Props.
(** ** Conjunction  To prove that [P /\ Q] holds, we must present evidence for both [P] and [Q].  Thus, it makes sense to define a proof object for [P /\ Q] as consisting of a pair of two proofs: one for [P] and another one for [Q]. This leads to the following definition. *)
Module And.
Inductive and (P Q : Prop) : Prop :=
| conj : P -> Q -> and P Q.
End And.
(** Notice the similarity with the definition of the [prod] type, given in chapter [Poly]; the only difference is that [prod] takes [Type] arguments, whereas [and] takes [Prop] arguments. *)
Print prod.
(* ===> Inductive prod (X Y : Type) : Type := | pair : X -> Y -> X * Y. *)
(** This should clarify why [destruct] and [intros] patterns can be used on a conjunctive hypothesis.  Case analysis allows us to consider all possible ways in which [P /\ Q] was proved -- here just one (the [conj] constructor).  Similarly, the [split] tactic actually works for any inductively defined proposition with only one constructor.  In particular, it works for [and]: *)

Lemma and_comm : forall P Q : Prop, P /\ Q <-> Q /\ P.
Definition and_comm'_aux P Q (H : P /\ Q) :=
match H with
| conj HP HQ => conj HQ HP
end.