Require Export Poly. Check (2 + 2 = 4). (* ===> 2 + 2 = 4 : Prop *) Check (ble_nat 3 2 = false). (* ===> ble_nat 3 2 = false : Prop *) (** Both provable and unprovable claims are perfectly good propositions. Simply _being_ a proposition is one thing; being _provable_ is something else! *) Check (2 + 2 = 5). (** We can define _parameterized propositions_. For example, what does it mean to claim that "a number n is even"? *) Definition even (n:nat) : Prop := evenb n = true. Check even. (* ===> even : nat -> Prop *) Check (even 4). (* ===> even 4 : Prop *) Check (even 3). (* ===> even 3 : Prop *) (** The type of [even], [nat->Prop], can be pronounced in three ways: (1) "[even] is a _function_ from numbers to propositions," (2) "[even] is a _family_ of propositions, indexed by a number [n]," or (3) "[even] is a _property_ of numbers." *) (** We can define them to take multiple arguments... *) Definition between (n m o: nat) : Prop := andb (ble_nat n o) (ble_nat o m) = true. (** The induction principle for natural numbers can be expressed using Props *) Definition true_for_zero (P:nat->Prop) : Prop := P 0. Definition preserved_by_S (P:nat->Prop) : Prop := forall n', P n' -> P (S n'). Definition true_for_all_numbers (P:nat->Prop) : Prop := forall n, P n. Definition our_nat_induction (P:nat->Prop) : Prop := (true_for_zero P) -> (preserved_by_S P) -> (true_for_all_numbers P). (* ##################################################### *) (** ** Inductively Defined Propositions *) Inductive good_day : day -> Prop := | gd_sat : good_day saturday | gd_sun : good_day sunday. (** The [Inductive] keyword means exactly the same thing whether we are using it to define sets of data values (in the [Type] world) or sets of evidence (in the [Prop] world). Consider the parts of the definition above: - The first line declares that [good_day] is a proposition indexed by a day. - The second line declares that the constructor [gd_sat] can be taken as evidence for the assertion [good_day saturday]. - The third line declares that the constructor [gd_sun] can be taken as evidence for the assertion [good_day sunday]. *) (** That is, we're _defining_ what we mean by days being good by saying "Saturday is good, sunday is good, and that's all." Then someone can _prove_ that Sunday is good simply by observing that we said it was when we defined what [good_day] meant. *) Theorem gds : good_day sunday. Proof. apply gd_sun. Qed. (** The constructor [gd_sun] is "primitive evidence" -- an _axiom_ -- justifying the claim that Sunday is good. *) (** Similarly, we can define a proposition [day_before] parameterized by _two_ days, together with axioms stating that Monday comes before Tuesday, Tuesday before Wednesday, and so on. *) Inductive day_before : day -> day -> Prop := | db_tue : day_before tuesday monday | db_wed : day_before wednesday tuesday | db_thu : day_before thursday wednesday | db_fri : day_before friday thursday | db_sat : day_before saturday friday | db_sun : day_before sunday saturday | db_mon : day_before monday sunday. (** The axioms that we introduce along with an inductively defined proposition can also involve universal quantifiers. For example, it is well known that _every_ day is a fine day for singing a song: *) Inductive fine_day_for_singing : day -> Prop := | fdfs_any : forall d:day, fine_day_for_singing d. (** The line above declares that, if [d] is a day, then [fdfs_any d] can be taken as evidence for [fine_day_for_singing d]. That is, we can construct evidence that [d] is a [fine_day_for_singing] by applying the constructor [fdfs_any] to [d]. In particular, Wednesday is a fine day for singing. *) Theorem fdfs_wed : fine_day_for_singing wednesday. Proof. apply fdfs_any. Qed. (** Some of the examples in the opening discussion of propositions involved the concept of _evenness_. We began with a computation [evenb n] that _checks_ evenness, yielding a boolean. From this, we built a proposition [even n] (defined in terms of [evenb]) that _asserts_ that [n] is even. That is, we defined "[n] is even" to mean "[evenb] returns [true] when applied to [n]." Another alternative is to define the concept of evenness directly. Instead of going indirectly via the [evenb] function ("a number is even if a certain computation yields [true]"), we can say directly what the concept of evenness means in terms of evidence. *) Inductive ev : nat -> Prop := | ev_0 : ev O | ev_SS : forall n:nat, ev n -> ev (S (S n)). (** This definition says that there are two ways to give evidence that a number [m] is even. First, [0] is even, and [ev_0] is evidence for this. Second, if [m = S (S n)] for some [n] and we can give evidence [e] that [n] is even, then [m] is also even, and [ev_SS n e] is the evidence. *) (** Later on we'll consider the tradeoffs of even(nat) or ev(nat) in setting up propositions. In PL settings, we'll often favor the latter over the former. *) (************************************************************* *) (** Coq's built-in logic is extremely small: [Inductive] definitions, universal quantification ([forall]), and implication ([->]) are primitive, but all the other familiar logical connectives -- conjunction, disjunction, negation, existential quantification, even equality -- can be defined using just these. *) (* ########################################################### *) (** * Quantification and Implication *) (** In fact, [->] and [forall] are the _same_ primitive! Coq's [->] notation is actually just a shorthand for [forall]. The [forall] notation is more general, because it allows us to _name_ the hypothesis. *) (** For example, consider this proposition: *) Definition funny_prop1 := forall n, forall (E : ev n), ev (n+4). (** If we had a proof term inhabiting this proposition, it would be a function with two arguments: a number [n] and some evidence that [n] is even. But the name [E] for this evidence is not used in the rest of the statement of [funny_prop1], so it's a bit silly to bother making up a name. We could write it like this instead: *) Definition funny_prop1' := forall n, forall (_ : ev n), ev (n+4). (** Or we can write it in more familiar notation: *) Definition funny_prop1'' := forall n, ev n -> ev (n+4). (** This illustrates that "[P -> Q]" is just syntactic sugar for "[forall (_:P), Q]". *) (* ########################################################### *) (** * Conjunction *) (** The logical conjunction of propositions [P] and [Q] is represented using an [Inductive] definition with one constructor. *) Inductive and (P Q : Prop) : Prop := conj : P -> Q -> (and P Q). (** The intuition behind this definition is simple: to construct evidence for [and P Q], we must provide evidence for [P] and evidence for [Q]. *) Notation "P /\ Q" := (and P Q) : type_scope. (** (The [type_scope] annotation tells Coq that this notation will be appearing in propositions, not values.) *) Check conj. (* ===> forall P Q : Prop, P -> Q -> P /\ Q *) (** Notice that it takes 4 inputs -- namely the propositions [P] and [Q] and evidence for [P] and [Q] -- and returns as output the evidence of [P /\ Q]. *) Theorem and_example : (ev 0) /\ (ev 4). Proof. apply conj. (* Case "left". *) apply ev_0. (* Case "right". *) apply ev_SS. apply ev_SS. apply ev_0. Qed. (** Just for convenience, we can use the tactic [split] as a shorthand for [apply conj]. *) Theorem and_example' : (ev 0) /\ (ev 4). Proof. split. Case "left". apply ev_0. Case "right". apply ev_SS. apply ev_SS. apply ev_0. Qed. (** Conversely, the [inversion] tactic can be used to take a conjunction hypothesis in the context, calculate what evidence must have been used to build it, and put this evidence into the proof context. *) Theorem proj1 : forall P Q : Prop, P /\ Q -> P. Proof. intros P Q H. inversion H as [HP HQ]. apply HP. Qed. Theorem and_commut : forall P Q : Prop, P /\ Q -> Q /\ P. Proof. (* WORKED IN CLASS *) intros P Q H. inversion H as [HP HQ]. split. (* Case "left". *) apply HQ. (* Case "right".*) apply HP. Qed. (* ###################################################### *) (** ** Iff *) (** The familiar logical "if and only if" is just the conjunction of two implications. *) Definition iff (P Q : Prop) := (P -> Q) /\ (Q -> P). Notation "P <-> Q" := (iff P Q) (at level 95, no associativity) : type_scope. Theorem iff_implies : forall P Q : Prop, (P <-> Q) -> P -> Q. Proof. intros P Q H. inversion H as [HAB HBA]. apply HAB. Qed. Theorem iff_sym : forall P Q : Prop, (P <-> Q) -> (Q <-> P). Proof. (* WORKED IN CLASS *) intros P Q H. inversion H as [HAB HBA]. split. Case "->". apply HBA. Case "<-". apply HAB. Qed. (** Some of Coq's tactics treat [iff] statements specially, thus avoiding the need for some low-level manipulation when reasoning with them. In particular, [rewrite] can be used with [iff] statements, not just equalities. *) (* ############################################################ *) (** * Disjunction *) (** Disjunction ("logical or") can also be defined as an inductive proposition. *) Inductive or (P Q : Prop) : Prop := | or_introl : P -> or P Q | or_intror : Q -> or P Q. Notation "P \/ Q" := (or P Q) : type_scope. Check or_introl. (* ===> forall P Q : Prop, P -> P \/ Q *) Check or_intror. (* ===> forall P Q : Prop, Q -> P \/ Q *) (** Since [P \/ Q] has two constructors, doing [inversion] on a hypothesis of type [P \/ Q] yields two subgoals. *) Theorem or_commut : forall P Q : Prop, P \/ Q -> Q \/ P. Proof. intros P Q H. inversion H as [HP | HQ]. Case "right". apply or_intror. apply HP. Case "left". apply or_introl. apply HQ. Qed. (** From here on, we'll use the shorthand tactics [left] and [right] in place of [apply or_introl] and [apply or_intror]. *) Theorem or_commut' : forall P Q : Prop, P \/ Q -> Q \/ P. Proof. intros P Q H. inversion H as [HP | HQ]. Case "right". right. apply HP. Case "left". left. apply HQ. Qed. (* ################################################### *) (** ** Relating [/\] and [\/] with [andb] and [orb] *) (** We've already seen several places where analogous structures can be found in Coq's computational ([Type]) and logical ([Prop]) worlds. Here is one more: the boolean operators [andb] and [orb] are obviously analogs, in some sense, of the logical connectives [/\] and [\/]. This analogy can be made more precise by the following theorems, which show how to translate knowledge about [andb] and [orb]'s behaviors on certain inputs into propositional facts about those inputs. *) Theorem andb_true__and : forall b c, andb b c = true -> b = true /\ c = true. Proof. (* WORKED IN CLASS *) intros b c H. destruct b. Case "b = true". destruct c. SCase "c = true". apply conj. reflexivity. reflexivity. SCase "c = false". inversion H. Case "b = false". inversion H. Qed. Theorem and__andb_true : forall b c, b = true /\ c = true -> andb b c = true. Proof. (* WORKED IN CLASS *) intros b c H. inversion H. rewrite H0. rewrite H1. reflexivity. Qed. (* ################################################### *) (** * Falsehood *) Inductive False : Prop := . (** Intuition: [False] is a proposition for which there is no way to give evidence. *) (** Since [False] has no constructors, inverting an assumption of type [False] always yields zero subgoals, allowing us to immediately prove any goal. *) Theorem False_implies_nonsense : False -> 2 + 2 = 5. Proof. intros contra. inversion contra. Qed. (** Conversely, the only way to prove [False] is if there is already something nonsensical or contradictory in the context: *) Theorem nonsense_implies_False : 2 + 2 = 5 -> False. Proof. intros contra. inversion contra. Qed. Theorem ex_falso_quodlibet : forall (P:Prop), False -> P. Proof. intros P contra. inversion contra. Qed. (** The Latin _ex falso quodlibet_ means, literally, "from falsehood follows whatever you please." This theorem is also known as the _principle of explosion_. *) (* #################################################### *) (** * Negation *) Definition not (P:Prop) := P -> False. (** The intuition is that, if [P] is not true, then anything at all (even [False]) follows from assuming [P]. *) Notation "~ x" := (not x) : type_scope. Check not. (* ===> Prop -> Prop *) (** It takes a little practice to get used to working with negation in Coq. Even though you can see perfectly well why something is true, it can be a little hard at first to get things into the right configuration so that Coq can see it! Here are proofs of a few familiar facts about negation to get you warmed up. *) Theorem not_False : ~ False. Proof. unfold not. intros H. inversion H. Qed. Theorem contradiction_implies_anything : forall P Q : Prop, (P /\ ~P) -> Q. Proof. (* WORKED IN CLASS *) intros P Q H. inversion H as [HP HNA]. unfold not in HNA. apply HNA in HP. inversion HP. Qed. Theorem double_neg : forall P : Prop, P -> ~~P. Proof. (* WORKED IN CLASS *) intros P H. unfold not. intros G. apply G. apply H. Qed. Theorem five_not_even : ~ ev 5. Proof. (* WORKED IN CLASS *) unfold not. intros Hev5. inversion Hev5 as [|n Hev3 Heqn]. inversion Hev3 as [|n' Hev1 Heqn']. inversion Hev1. Qed. (** Note that some theorems that are true in classical logic are _not_ provable in Coq's "built in" constructive logic... *) Theorem classic_double_neg : forall P : Prop, ~~P -> P. Proof. (* WORKED IN CLASS *) intros P H. unfold not in H. (* But now what? There is no way to "invent" evidence for [P]. *) Admitted. (* ########################################################## *) (** ** Inequality *) (** Saying [x <> y] is just the same as saying [~(x = y)]. *) Notation "x <> y" := (~ (x = y)) : type_scope. (** Since inequality involves a negation, it again requires a little practice to be able to work with it fluently. Here is one very useful trick. If you are trying to prove a goal that is nonsensical (e.g., the goal state is [false = true]), apply the lemma [ex_falso_quodlibet] to change the goal to [False]. This makes it easier to use assumptions of the form [~P] that are available in the context -- in particular, assumptions of the form [x<>y]. *) Theorem not_false_then_true : forall b : bool, b <> false -> b = true. Proof. intros b H. destruct b. Case "b = true". reflexivity. Case "b = false". unfold not in H. apply ex_falso_quodlibet. apply H. reflexivity. Qed. (* ############################################################ *) (** * Existential Quantification *) Inductive ex (X:Type) (P : X->Prop) : Prop := ex_intro : forall (witness:X), P witness -> ex X P. (** That is, [ex] is a family of propositions indexed by a type [X] and a property [P] over [X]. In order to give evidence for the assertion "there exists an [x] for which the property [P] holds" we must actually name a _witness_ -- a specific value [x] -- and then give evidence for [P x], i.e., evidence that [x] has the property [P]. For example, consider this existentially quantified proposition: *) Definition some_nat_is_even : Prop := ex nat ev. Definition snie : some_nat_is_even := ex_intro _ ev 4 (ev_SS 2 (ev_SS 0 ev_0)). Notation "'exists' x , p" := (ex _ (fun x => p)) (at level 200, x ident, right associativity) : type_scope. Notation "'exists' x : X , p" := (ex _ (fun x:X => p)) (at level 200, x ident, right associativity) : type_scope. Example exists_example_1 : exists n, n + (n * n) = 6. Proof. apply ex_intro with (witness:=2). reflexivity. Qed. (** Or, instead of writing [apply ex_intro with (witness:=e)] all the time, we can use the convenient shorthand [exists e], which means the same thing. *) Example exists_example_1' : exists n, n + (n * n) = 6. Proof. exists 2. reflexivity. Qed. Theorem exists_example_2 : forall n, (exists m, n = 4 + m) -> (exists o, n = 2 + o). Proof. intros n H. inversion H as [m Hm]. exists (2 + m). apply Hm. Qed. (* ###################################################### *) (** * Equality *) (** Even Coq's equality relation is not built in. It has the following inductive definition. (We enclose the definition in a module to avoid confusion with the standard library equality, which we have used extensively already.) *) Module MyEquality. Inductive eq (X:Type) : X -> X -> Prop := refl_equal : forall x, eq X x x. (** Standard infix notation (using Coq's type argument synthesis): *) Notation "x = y" := (eq _ x y) (at level 70, no associativity) : type_scope. (** Here is a slightly different definition -- the one that actually appears in the Coq standard library. *) Inductive eq' (X:Type) (x:X) : X -> Prop := refl_equal' : eq' X x x. Notation "x =' y" := (eq' _ x y) (at level 70, no associativity) : type_scope. Definition four : 2 + 2 = 1 + 3 := refl_equal nat 4. Definition singleton : forall (X:Set) (x:X), []++[x] = x::[] := fun (X:Set) (x:X) => refl_equal (list X) [x]. End MyEquality. (* ####################################################### *) (** ** Inversion, Again *) (** In general, the [inversion] tactic - takes a hypothesis [H] whose type [P] is inductively defined, and - for each constructor [C] in [P]'s definition, - generates a new subgoal in which we assume [H] was built with [C], - adds the arguments (premises) of [C] to the context of the subgoal as extra hypotheses, - matches the conclusion (result type) of [C] against the current goal and calculates a set of equalities that must hold in order for [C] to be applicable, - adds these equalities to the context of the subgoal, and - if the equalities are not satisfiable (e.g., they involve things like [S n = O]), immediately solves the subgoal. _Example_: If we invert a hypothesis built with [or], there are two constructors, so two subgoals get generated. The conclusion (result type) of the constructor ([P \/ Q]) doesn't place any restrictions on the form of [P] or [Q], so we don't get any extra equalities in the context of the subgoal. _Example_: If we invert a hypothesis built with [and], there is only one constructor, so only one subgoal gets generated. Again, the conclusion (result type) of the constructor ([P /\ Q]) doesn't place any restrictions on the form of [P] or [Q], so we don't get any extra equalities in the context of the subgoal. The constructor does have two arguments, though, and these can be seen in the context in the subgoal. _Example_: If we invert a hypothesis built with [eq], there is again only one constructor, so only one subgoal gets generated. Now, though, the form of the [refl_equal] constructor does give us some extra information: it tells us that the two arguments to [eq] must be the same! The [inversion] tactic adds this fact to the context. *) (* ##################################################### *) (** ** Induction Principles for Inductively Defined Types *) (** Every time we declare a new [Inductive] datatype, Coq automatically generates an axiom that embodies an _induction principle_ for this type. *) Check nat_ind. (** Note that this is exactly the [our_nat_induction] property from above. *) (** The [induction] tactic is a straightforward wrapper that, at its core, simply performs [apply t_ind]. *) Theorem mult_0_r' : forall n:nat, n * 0 = 0. Proof. apply nat_ind. Case "O". reflexivity. Case "S". simpl. intros n IHn. rewrite -> IHn. reflexivity. Qed. (** The induction principles that Coq generates for other datatypes defined with [Inductive] follow a similar pattern. If we define a type [t] with constructors [c1] ... [cn], Coq generates a theorem with this shape: [[ t_ind : forall P : t -> Prop, ... case for c1 ... -> ... case for c2 ... -> ... -> ... case for cn ... -> forall n : t, P n ]] *) Inductive yesno : Type := | yes : yesno | no : yesno. Check yesno_ind. Inductive natlist : Type := | nnil : natlist | ncons : nat -> natlist -> natlist. Check natlist_ind. (** From these examples, we can extract this general rule: - The type declaration gives several constructors; each corresponds to one clause of the induction principle. - Each constructor [c] takes argument types [a1]...[an]. - Each [ai] can be either [t] (the datatype we are defining) or some other type [s]. - The corresponding case of the induction principle says (in English): - "for all values [x1]...[xn] of types [a1]...[an], if [P] holds for each of the [x]s of type [t], then [P] holds for [c x1 ... xn]". *) (* ####################################################### *) (** * Relations as Propositions *) Module LeFirstTry. Inductive le : nat -> nat -> Prop := | le_n : forall n, le n n | le_S : forall n m, (le n m) -> (le n (S m)). (* Induction principle: le_ind : forall P : nat -> nat -> Prop, (forall n : nat, P n n) -> (forall n m : nat, le n m -> P n m -> P n (S m)) -> forall n n0 : nat, le n n0 -> P n n0 *) End LeFirstTry. Inductive le (n:nat) : nat -> Prop := | le_n : le n n | le_S : forall m, (le n m) -> (le n (S m)). Notation "m <= n" := (le m n). (** The second one is better, even though it looks less symmetric. Why? Because it gives us a simpler induction principle. (The same was true of our second version of [eq].) *) Check le_ind. (** Here are some sanity checks on the definition. (Notice that, although these are the same kind of simple "unit tests" as we gave for the testing functions we wrote in the first few lectures, we must construct their proofs explicitly -- [simpl] and [reflexivity] don't do the job, because the proofs aren't just a matter of simplifying computations. *) Theorem test_le1 : 3 <= 3. Proof. (* WORKED IN CLASS *) apply le_n. Qed. Theorem test_le2 : 3 <= 6. Proof. (* WORKED IN CLASS *) apply le_S. apply le_S. apply le_S. apply le_n. Qed. Theorem test_le3 : ~ (2 <= 1). Proof. (* WORKED IN CLASS *) intros H. inversion H. inversion H1. Qed. (** The "strictly less than" relation [n < m] can now be defined in terms of [le]. *) Definition lt (n m:nat) := le (S n) m. Notation "m < n" := (lt m n). (** Here are a few more simple relations on numbers: *) Inductive square_of : nat -> nat -> Prop := sq : forall n:nat, square_of n (n * n). Inductive next_nat (n:nat) : nat -> Prop := | nn : next_nat n (S n). Inductive next_even (n:nat) : nat -> Prop := | ne_1 : ev (S n) -> next_even n (S n) | ne_2 : ev (S (S n)) -> next_even n (S (S n)).