(** * Logic: Logic in Coq *)
Set Warnings "-notation-overridden,-parsing".
Require Export Tactics.
(** In previous chapters, we have seen many examples of factual claims (_propositions_) and ways of presenting evidence of their truth (_proofs_).  In particular, we have worked extensively with _equality propositions_ of the form [e1 = e2], with implications ([P -> Q]), and with quantified propositions ([forall x, P]).  In this chapter, we will see how Coq can be used to carry out other familiar forms of logical reasoning.  Before diving into details, let's talk a bit about the status of mathematical statements in Coq.  Recall that Coq is a _typed_ language, which means that every sensible expression in its world has an associated type.  Logical claims are no exception: any statement we might try to prove in Coq has a type, namely [Prop], the type of _propositions_.  We can see this with the [Check] command: *)
Check 3 = 3.
(* ===> Prop *)
Check forall n m : nat, n + m = m + n.
(* ===> Prop *)
(** Note that _all_ syntactically well-formed propositions have type [Prop] in Coq, regardless of whether they are true or not.  Simply _being_ a proposition is one thing; being _provable_ is something else! *)
Check forall n : nat, n = 2.
(* ===> Prop *)
Check 3 = 4.
(* ===> Prop *)
(** Indeed, propositions don't just have types: they are _first-class objects_ that can be manipulated in the same ways as the other entities in Coq's world.  So far, we've seen one primary place that propositions can appear: in [Theorem] (and [Lemma] and [Example]) declarations. *)
(** The equality operator [=] is also a function that returns a [Prop].  The expression [n = m] is syntactic sugar for [eq n m], defined using Coq's [Notation] mechanism. Because [eq] can be used with elements of any type, it is also polymorphic: *)
Check @eq.
(* ===> forall A : Type, A -> A -> Prop *)
(** (Notice that we wrote [@eq] instead of [eq]: The type argument [A] to [eq] is declared as implicit, so we need to turn off implicit arguments to see the full type of [eq].) *)
(* ################################################################# *)
(** * Logical Connectives *)
(* ================================================================= *)
(** ** Conjunction *)
(** The _conjunction_ (or _logical and_) of propositions [A] and [B] is written [A /\ B], representing the claim that both [A] and [B] are true. *)
Example and_example : 3 + 4 = 7 /\ 2 * 2 = 4.
(** To prove a conjunction, use the [split] tactic.  It will generate two subgoals, one for each part of the statement: *)
(** For any propositions [A] and [B], if we assume that [A] is true and we assume that [B] is true, we can conclude that [A /\ B] is also true. *)
(** Since applying a theorem with hypotheses to some goal has the effect of generating as many subgoals as there are hypotheses for that theorem, we can apply [and_intro] to achieve the same effect as [split]. *)
Example and_example' : 3 + 4 = 7 /\ 2 * 2 = 4.
(** **** Exercise: 2 stars (and_exercise)  *)
Example and_exercise :
forall n m : nat, n + m = 0 -> n = 0 /\ m = 0.
(** As usual, we can also destruct [H] right when we introduce it, instead of introducing and then destructing it: *)

Lemma and_example2' :
forall n m : nat, n = 0 /\ m = 0 -> n + m = 0.