(** * 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: *)
(** You may wonder why we bothered packing the two hypotheses [n = 0] and [m = 0] into a single conjunction, since we could have also stated the theorem with two separate premises: *)
(** For this theorem, both formulations are fine.  But it's important to understand how to work with conjunctive hypotheses because conjunctions often arise from intermediate steps in proofs, especially in bigger developments.  Here's a simple example: *)

Lemma and_example3 :
forall n m : nat, n + m = 0 -> n * m = 0.