(** * 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. *)
(** You can "use theorems as functions" in this way with almost all tactics that take a theorem name as an argument.  Note also that theorem application uses the same inference mechanisms as function application; thus, it is possible, for example, to supply wildcards as arguments to be inferred, or to declare some hypotheses to a theorem as implicit by default.  These features are illustrated in the proof below. *)
Example lemma_application_ex :
forall {n : nat} {ns : list nat},
In n (map (fun m => m * 0) ns) ->
n = 0.
(** We will see many more examples of the idioms from this section in later chapters. *)
(* ################################################################# *)
(** * Coq vs. Set Theory *)
(** Coq's logical core, the _Calculus of Inductive Constructions_, differs in some important ways from other formal systems that are used by mathematicians for writing down precise and rigorous proofs.  For example, in the most popular foundation for mainstream paper-and-pencil mathematics, Zermelo-Fraenkel Set Theory (ZFC), a mathematical object can potentially be a member of many different sets; a term in Coq's logic, on the other hand, is a member of at most one type.  This difference often leads to slightly different ways of capturing informal mathematical concepts, but these are, by and large, quite natural and easy to work with.  For example, instead of saying that a natural number [n] belongs to the set of even numbers, we would say in Coq that [ev n] holds, where [ev : nat -> Prop] is a property describing even numbers.  However, there are some cases where translating standard mathematical reasoning into Coq can be either cumbersome or sometimes even impossible, unless we enrich the core logic with additional axioms.  We conclude this chapter with a brief discussion of some of the most significant differences between the two worlds. *)
(* ================================================================= *)
(** ** Functional Extensionality *)
(** The equality assertions that we have seen so far mostly have concerned elements of inductive types ([nat], [bool], etc.).  But since Coq's equality operator is polymorphic, these are not the only possibilities -- in particular, we can write propositions claiming that two _functions_ are equal to each other: *)
Example function_equality_ex1 : plus 3 = plus (pred 4).
(** Naturally, we must be careful when adding new axioms into Coq's logic, as they may render it _inconsistent_ -- that is, they may make it possible to prove every proposition, including [False]!  Unfortunately, there is no simple way of telling whether an axiom is safe to add: hard work is generally required to establish the consistency of any particular combination of axioms.  However, it is known that adding functional extensionality, in particular, _is_ consistent.  To check whether a particular proof relies on any additional axioms, use the [Print Assumptions] command.  *)
Print Assumptions function_equality_ex2.
(* ===> Axioms: functional_extensionality : forall (X Y : Type) (f g : X -> Y), (forall x : X, f x = g x) -> f = g *)
(** **** Exercise: 4 stars (tr_rev)  *)
(** One problem with the definition of the list-reversing function [rev] that we have is that it performs a call to [app] on each step; running [app] takes time asymptotically linear in the size of the list, which means that [rev] has quadratic running time. We can improve this with the following definition: *)
Fixpoint rev_append {X} (l1 l2 : list X) : list X :=
match l1 with
| [] => l2
| x :: l1' => rev_append l1' (x :: l2)
end.
Definition tr_rev {X} (l : list X) : list X :=
rev_append l [].
(** This version is said to be _tail-recursive_, because the recursive call to the function is the last operation that needs to be performed (i.e., we don't have to execute [++] after the recursive call); a decent compiler will generate very efficient code in this case.  Prove that the two definitions are indeed equivalent. *)

Lemma tr_rev_correct : forall X, @tr_rev X = @rev X.