(** * 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: *)
(** Another common situation with conjunctions is that we know [A /\ B] but in some context we need just [A] (or just [B]). The following lemmas are useful in such cases: *)
(** Conversely, to show that a disjunction holds, we need to show that one of its sides does. This is done via two tactics, [left] and [right].  As their names imply, the first one requires proving the left side of the disjunction, while the second requires proving its right side.  Here is a trivial use... *)
(** ... and a slightly more interesting example requiring both [left] and [right]: *)
(** Such inequality statements are frequent enough to warrant a special notation, [x <> y]: *)
Check (0 <> 1).
(* ===> Prop *)
(** It takes a little practice to get used to working with negation in Coq.  Even though you can see perfectly well why a statement involving negation is true, it can be a little tricky at first to get things into the right configuration so that Coq can understand it!  Here are proofs of a few familiar facts to get you warmed up. *)
(** Since reasoning with [ex_falso_quodlibet] is quite common, Coq provides a built-in tactic, [exfalso], for applying it. *)
(* ================================================================= *)
(** ** Truth *)
(** Besides [False], Coq's standard library also defines [True], a proposition that is trivially true. To prove it, we use the predefined constant [I : True]: *)
(** **** Exercise: 1 star, optional (iff_properties)  *)
(** Using the above proof that [<->] is symmetric ([iff_sym]) as a guide, prove that it is also reflexive and transitive. *)
(** We can now use these facts with [rewrite] and [reflexivity] to give smooth proofs of statements involving equivalences.  Here is a ternary version of the previous [mult_0] result: *)
(** The [apply] tactic can also be used with [<->]. When given an equivalence as its argument, [apply] tries to guess which side of the equivalence to use. *)
(* ================================================================= *)
(** ** Existential Quantification *)
(** Another important logical connective is _existential quantification_.  To say that there is some [x] of type [T] such that some property [P] holds of [x], we write [exists x : T, P]. As with [forall], the type annotation [: T] can be omitted if Coq is able to infer from the context what the type of [x] should be. *)
(** To prove a statement of the form [exists x, P], we must show that [P] holds for some specific choice of value for [x], known as the _witness_ of the existential.  This is done in two steps: First, we explicitly tell Coq which witness [t] we have in mind by invoking the tactic [exists t].  Then we prove that [P] holds after all occurrences of [x] are replaced by [t]. *)
(** Conversely, if we have an existential hypothesis [exists x, P] in the context, we can destruct it to obtain a witness [x] and a hypothesis stating that [P] holds of [x]. *)
Example In_example_2 :
forall n, In n [2; 4] ->
exists n', n = 2 * n'.
(** (Notice the use of the empty pattern to discharge the last case _en passant_.) *)
(** We can also prove more generic, higher-level lemmas about [In].  Note, in the next, how [In] starts out applied to a variable and only gets expanded when we do case analysis on this variable: *)
(** This way of defining propositions recursively, though convenient in some cases, also has some drawbacks.  In particular, it is subject to Coq's usual restrictions regarding the definition of recursive functions, e.g., the requirement that they be "obviously terminating."  In the next chapter, we will see how to define propositions _inductively_, a different technique with its own set of strengths and limitations. *)
(** A more elegant alternative is to apply [plus_comm] directly to the arguments we want to instantiate it with, in much the same way as we apply a polymorphic function to a type argument. *)

Lemma plus_comm3_take3 :
forall n m p, n + (m + p) = (p + m) + n.