-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLogic.v
1511 lines (1241 loc) · 51.2 KB
/
Logic.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(** * Logic: Logic in Coq *)
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 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. *)
Theorem plus_2_2_is_4 :
2 + 2 = 4.
Proof. reflexivity. Qed.
(** But propositions can be used in many other ways. For example, we
can give a name to a proposition using a [Definition], just as we
have given names to expressions of other sorts. *)
Definition plus_fact : Prop := 2 + 2 = 4.
Check plus_fact.
(* ===> plus_fact : Prop *)
(** We can later use this name in any situation where a proposition is
expected -- for example, as the claim in a [Theorem] declaration. *)
Theorem plus_fact_is_true :
plus_fact.
Proof. reflexivity. Qed.
(** We can also write _parameterized_ propositions -- that is,
functions that take arguments of some type and return a
proposition. For instance, the following function takes a number
and returns a proposition asserting that this number is equal to
three: *)
Definition is_three (n : nat) : Prop :=
n = 3.
Check is_three.
(* ===> nat -> Prop *)
(** In Coq, functions that return propositions are said to define
_properties_ of their arguments. For instance, here's a
polymorphic property defining the familiar notion of an _injective
function_. *)
Definition injective {A B} (f : A -> B) :=
forall x y : A, f x = f y -> x = y.
Lemma succ_inj : injective S.
Proof.
intros n m H. inversion H. reflexivity.
Qed.
(** The equality operator [=] that we have been using so far is also
just a function that returns a [Prop]. The expression [n = m] is
just syntactic sugar for [eq n m], defined using Coq's [Notation]
mechanism. Because [=] 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], denoting 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. Its effect is to
generate two subgoals, one for each part of the statement: *)
Proof.
split.
- (* 3 + 4 = 7 *) reflexivity.
- (* 2 + 2 = 4 *) reflexivity.
Qed.
(** More generally, the following principle works for any two
propositions [A] and [B]: *)
Lemma and_intro : forall A B : Prop, A -> B -> A /\ B.
Proof.
intros A B HA HB. split.
- apply HA.
- apply HB.
Qed.
(** A logical statement with multiple arrows is just a theorem that
has several hypotheses. Here, [and_intro] says that, for any
propositions [A] and [B], if we assume that [A] is true and we
assume that [B] is true, then [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.
Proof.
apply and_intro.
- (* 3 + 4 = 7 *) reflexivity.
- (* 2 + 2 = 4 *) reflexivity.
Qed.
(** **** Exercise: 2 stars (and_exercise) *)
Example and_exercise :
forall n m : nat, n + m = 0 -> n = 0 /\ m = 0.
Proof.
intros. split.
-destruct n.
+ reflexivity.
+ simpl in H. inversion H.
-destruct m.
+ reflexivity.
+ rewrite <- plus_n_Sm in H. inversion H.
Qed.
(** [] *)
(** So much for proving conjunctive statements. To go in the other
direction -- i.e., to _use_ a conjunctive hypothesis to prove
something else -- we employ the [destruct] tactic.
If the proof context contains a hypothesis [H] of the form [A /\
B], writing [destruct H as [HA HB]] will remove [H] from the
context and add two new hypotheses: [HA], stating that [A] is
true, and [HB], stating that [B] is true. For instance: *)
Lemma and_example2 :
forall n m : nat, n = 0 /\ m = 0 -> n + m = 0.
Proof.
intros n m H.
destruct H as [Hn Hm].
rewrite Hn. rewrite Hm.
reflexivity.
Qed.
(** As usual, we can also destruct [H] 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.
Proof.
intros n m [Hn Hm].
rewrite Hn. rewrite Hm.
reflexivity.
Qed.
(** 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: *)
Lemma and_example2'' :
forall n m : nat, n = 0 -> m = 0 -> n + m = 0.
Proof.
intros n m Hn Hm.
rewrite Hn. rewrite Hm.
reflexivity.
Qed.
(** In this case, there is not much difference between the two
theorems. But it is often necessary to explicitly decompose
conjunctions that arise from intermediate steps in proofs,
especially in bigger developments. Here's a simplified
example: *)
Lemma and_example3 :
forall n m : nat, n + m = 0 -> n * m = 0.
Proof.
intros n m H.
assert (H' : n = 0 /\ m = 0).
{ apply and_exercise. apply H. }
destruct H' as [Hn Hm].
rewrite Hn. reflexivity.
Qed.
(** 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: *)
Lemma proj1 : forall P Q : Prop,
P /\ Q -> P.
Proof.
intros P Q [HP HQ].
apply HP. Qed.
(** **** Exercise: 1 star, optional (proj2) *)
Lemma proj2 : forall P Q : Prop,
P /\ Q -> Q.
Proof.
intros p q [HP HQ]. apply HQ.
Qed.
(** [] *)
(** Finally, we sometimes need to rearrange the order of conjunctions
and/or the grouping of conjuncts in multi-way conjunctions. The
following commutativity and associativity theorems come in handy
in such cases. *)
Theorem and_commut : forall P Q : Prop,
P /\ Q -> Q /\ P.
Proof.
(* WORKED IN CLASS *)
intros P Q [HP HQ].
split.
- (* left *) apply HQ.
- (* right *) apply HP. Qed.
(** **** Exercise: 2 stars (and_assoc) *)
(** (In the following proof of associativity, notice how the _nested_
intro pattern breaks the hypothesis [H : P /\ (Q /\ R)] down into
[HP : P], [HQ : Q], and [HR : R]. Finish the proof from
there.) *)
Theorem and_assoc : forall P Q R : Prop,
P /\ (Q /\ R) -> (P /\ Q) /\ R.
Proof.
intros P Q R [HP [HQ HR]].
split.
- split.
+ apply HP.
+ apply HQ.
- apply HR.
Qed.
(** [] *)
(** By the way, the infix notation [/\] is actually just syntactic
sugar for [and A B]. That is, [and] is a Coq operator that takes
two propositions as arguments and yields a proposition. *)
Check and.
(* ===> and : Prop -> Prop -> Prop *)
(* ================================================================= *)
(** ** Disjunction *)
(** Another important connective is the _disjunction_, or _logical or_
of two propositions: [A \/ B] is true when either [A] or [B]
is. (Alternatively, we can write [or A B], where [or : Prop ->
Prop -> Prop].)
To use a disjunctive hypothesis in a proof, we proceed by case
analysis, which, as for [nat] or other data types, can be done
with [destruct] or [intros]. Here is an example: *)
Lemma or_example :
forall n m : nat, n = 0 \/ m = 0 -> n * m = 0.
Proof.
(* This pattern implicitly does case analysis on
[n = 0 \/ m = 0] *)
intros n m [Hn | Hm].
- (* Here, [n = 0] *)
rewrite Hn. reflexivity.
- (* Here, [m = 0] *)
rewrite Hm. rewrite <- mult_n_O.
reflexivity.
Qed.
(** We can see in this example that, when we perform case analysis on
a disjunction [A \/ B], we must satisfy two proof obligations,
each showing that the conclusion holds under a different
assumption -- [A] in the first subgoal and [B] in the second.
Note that the case analysis pattern ([Hn | Hm]) allows us to name
the hypothesis that is generated in each subgoal.
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... *)
Lemma or_intro : forall A B : Prop, A -> A \/ B.
Proof.
intros A B HA.
left.
apply HA.
Qed.
(** ... and a slightly more interesting example requiring the use of
both [left] and [right]: *)
Lemma zero_or_succ :
forall n : nat, n = 0 \/ n = S (pred n).
Proof.
intros [|n].
- left. reflexivity.
- right. reflexivity.
Qed.
(** **** Exercise: 1 star (mult_eq_0) *)
Lemma mult_eq_0 :
forall n m, n * m = 0 -> n = 0 \/ m = 0.
Proof.
intros. destruct n.
- left. reflexivity.
- right. destruct m.
+ reflexivity.
+ inversion H.
Qed.
(** [] *)
(** **** Exercise: 1 star (or_commut) *)
Theorem or_commut : forall P Q : Prop,
P \/ Q -> Q \/ P.
Proof.
intros. destruct H.
- right. apply H.
- left. apply H.
Qed.
(** [] *)
(* ================================================================= *)
(** ** Falsehood and Negation *)
(** So far, we have mostly been concerned with proving that certain
things are _true_ -- addition is commutative, appending lists is
associative, etc. Of course, we may also be interested in
_negative_ results, showing that certain propositions are _not_
true. In Coq, such negative statements are expressed with the
negation operator [~].
To see how negation works, recall the discussion of the _principle
of explosion_ from the [Tactics] chapter; it asserts that, if we
assume a contradiction, then any other proposition can be derived.
Following this intuition, we could define [~ P] ("not [P]") as
[forall Q, P -> Q]. Coq actually makes a slightly different
choice, defining [~ P] as [P -> False], where [False] is a
_particular_ contradictory proposition defined in the standard
library. *)
Module MyNot.
Definition not (P:Prop) := P -> False.
Notation "~ x" := (not x) : type_scope.
Check not.
(* ===> Prop -> Prop *)
End MyNot.
(** Since [False] is a contradictory proposition, the principle of
explosion also applies to it. If we get [False] into the proof
context, we can [destruct] it to complete any goal: *)
Theorem ex_falso_quodlibet : forall (P:Prop),
False -> P.
Proof.
(* WORKED IN CLASS *)
intros P contra.
destruct contra. Qed.
(** The Latin _ex falso quodlibet_ means, literally, "from falsehood
follows whatever you like"; this is another common name for the
principle of explosion. *)
(** **** Exercise: 2 stars, optional (not_implies_our_not) *)
(** Show that Coq's definition of negation implies the intuitive one
mentioned above: *)
Fact not_implies_our_not : forall (P:Prop),
~ P -> (forall (Q:Prop), P -> Q).
Proof.
intros. destruct H. apply H0.
Qed.
(** [] *)
(** This is how we use [not] to state that [0] and [1] are different
elements of [nat]: *)
Theorem zero_not_one : ~(0 = 1).
Proof.
intros contra. inversion contra.
Qed.
(** Such inequality statements are frequent enough to warrant a
special notation, [x <> y]: *)
Check (0 <> 1).
(* ===> Prop *)
Theorem zero_not_one' : 0 <> 1.
Proof.
intros H. inversion H.
Qed.
(** 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. *)
Theorem not_False :
~ False.
Proof.
unfold not. intros H. destruct H. Qed.
Theorem contradiction_implies_anything : forall P Q : Prop,
(P /\ ~P) -> Q.
Proof.
(* WORKED IN CLASS *)
intros P Q [HP HNA]. unfold not in HNA.
apply HNA in HP. destruct 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.
(** **** Exercise: 2 stars, advanced, recommended (double_neg_inf) *)
(** Write an informal proof of [double_neg]:
_Theorem_: [P] implies [~~P], for any proposition [P].
_Proof_:
(* FILL IN HERE *)
[]
*)
(** **** Exercise: 2 stars, recommended (contrapositive) *)
Theorem contrapositive : forall P Q : Prop,
(P -> Q) -> (~Q -> ~P).
Proof.
intros. intros H1. destruct H0. apply H. apply H1.
Qed.
(** [] *)
(** **** Exercise: 1 star (not_both_true_and_false) *)
Theorem not_both_true_and_false : forall P : Prop,
~ (P /\ ~P).
Proof.
unfold not. intros. apply H. destruct H. apply H.
Qed.
(** [] *)
(** **** Exercise: 1 star, advanced (informal_not_PNP) *)
(** Write an informal proof (in English) of the proposition [forall P
: Prop, ~(P /\ ~P)]. *)
(* FILL IN HERE *)
(** [] *)
(** Similarly, since inequality involves a negation, it requires a
little practice to be able to work with it fluently. Here is one
useful trick. If you are trying to prove a goal that is
nonsensical (e.g., the goal state is [false = true]), apply
[ex_falso_quodlibet] to change the goal to [False]. This makes it
easier to use assumptions of the form [~P] that may be available
in the context -- in particular, assumptions of the form
[x<>y]. *)
Theorem not_true_is_false : forall b : bool,
b <> true -> b = false.
Proof.
intros [] H.
- (* b = true *)
unfold not in H.
apply ex_falso_quodlibet.
apply H. reflexivity.
- (* b = false *)
reflexivity.
Qed.
(** Since reasoning with [ex_falso_quodlibet] is quite common, Coq
provides a built-in tactic, [exfalso], for applying it. *)
Theorem not_true_is_false' : forall b : bool,
b <> true -> b = false.
Proof.
intros [] H.
- (* b = false *)
unfold not in H.
exfalso. (* <=== *)
apply H. reflexivity.
- (* b = true *) reflexivity.
Qed.
(* ================================================================= *)
(** ** 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]: *)
Lemma True_is_true : True.
Proof. apply I. Qed.
(** Unlike [False], which is used extensively, [True] is used quite
rarely, since it is trivial (and therefore uninteresting) to prove
as a goal, and it carries no useful information as a hypothesis.
But it can be quite useful when defining complex [Prop]s using
conditionals or as a parameter to higher-order [Prop]s. We will
see some examples such uses of [True] later on. *)
(* ================================================================= *)
(** ** Logical Equivalence *)
(** The handy "if and only if" connective, which asserts that two
propositions have the same truth value, is just the conjunction of
two implications. *)
Module MyIff.
Definition iff (P Q : Prop) := (P -> Q) /\ (Q -> P).
Notation "P <-> Q" := (iff P Q)
(at level 95, no associativity)
: type_scope.
End MyIff.
Theorem iff_sym : forall P Q : Prop,
(P <-> Q) -> (Q <-> P).
Proof.
(* WORKED IN CLASS *)
intros P Q [HAB HBA].
split.
- (* -> *) apply HBA.
- (* <- *) apply HAB. Qed.
Lemma not_true_iff_false : forall b,
b <> true <-> b = false.
Proof.
(* WORKED IN CLASS *)
intros b. split.
- (* -> *) apply not_true_is_false.
- (* <- *)
intros H. rewrite H. intros H'. inversion H'.
Qed.
(** **** 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. *)
Theorem iff_refl : forall P : Prop,
P <-> P.
Proof.
(* FILL IN HERE *) Admitted.
Theorem iff_trans : forall P Q R : Prop,
(P <-> Q) -> (Q <-> R) -> (P <-> R).
Proof.
intros. unfold iff. split.
- unfold iff in H. unfold iff in H0. destruct H.
destruct H0. intros. apply H0. apply H. apply H3.
- unfold iff in H. unfold iff in H0. destruct H. destruct H0.
intros. apply H1. apply H2. apply H3.
Qed.
(** [] *)
(** **** Exercise: 3 stars (or_distributes_over_and) *)
Theorem or_distributes_over_and : forall P Q R : Prop,
P \/ (Q /\ R) <-> (P \/ Q) /\ (P \/ R).
Proof.
intros. split.
- intros. split.
+ destruct H.
*left. apply H.
*right. destruct H. apply H.
+ destruct H.
* left. apply H.
* destruct H. right. apply H0.
-intros [[H1P | H1Q] [H2P | H2R]].
+ left. apply H1P.
+ left. apply H1P.
+ left. apply H2P.
+ right. split.
* apply H1Q.
* apply H2R.
Qed.
(** [] *)
(** Some of Coq's tactics treat [iff] statements specially, avoiding
the need for some low-level proof-state manipulation. In
particular, [rewrite] and [reflexivity] can be used with [iff]
statements, not just equalities. To enable this behavior, we need
to import a special Coq library that allows rewriting with other
formulas besides equality: *)
Require Import Coq.Setoids.Setoid.
(** Here is a simple example demonstrating how these tactics work with
[iff]. First, let's prove a couple of basic iff equivalences: *)
Lemma mult_0 : forall n m, n * m = 0 <-> n = 0 \/ m = 0.
Proof.
split.
- apply mult_eq_0.
- apply or_example.
Qed.
Lemma or_assoc :
forall P Q R : Prop, P \/ (Q \/ R) <-> (P \/ Q) \/ R.
Proof.
intros P Q R. split.
- intros [H | [H | H]].
+ left. left. apply H.
+ left. right. apply H.
+ right. apply H.
- intros [[H | H] | H].
+ left. apply H.
+ right. left. apply H.
+ right. right. apply H.
Qed.
(** 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: *)
Lemma mult_0_3 :
forall n m p, n * m * p = 0 <-> n = 0 \/ m = 0 \/ p = 0.
Proof.
intros n m p.
rewrite mult_0. rewrite mult_0. rewrite or_assoc.
reflexivity.
Qed.
(** 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. *)
Lemma apply_iff_example :
forall n m : nat, n * m = 0 -> n = 0 \/ m = 0.
Proof.
intros n m H. apply mult_0. apply H.
Qed.
(* ================================================================= *)
(** ** 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]. Here is an example: *)
Lemma four_is_even : exists n : nat, 4 = n + n.
Proof.
exists 2. reflexivity.
Qed.
(** 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]. *)
Theorem exists_example_2 : forall n,
(exists m, n = 4 + m) ->
(exists o, n = 2 + o).
Proof.
intros n [m Hm].
exists (2 + m).
apply Hm. Qed.
(** **** Exercise: 1 star (dist_not_exists) *)
(** Prove that "[P] holds for all [x]" implies "there is no [x] for
which [P] does not hold." *)
Theorem dist_not_exists : forall (X:Type) (P : X -> Prop),
(forall x, P x) -> ~ (exists x, ~ P x).
Proof.
unfold not. intros. destruct H0. apply H0 in H. apply H.
Qed.
(** [] *)
(** **** Exercise: 2 stars (dist_exists_or) *)
(** Prove that existential quantification distributes over
disjunction. *)
Theorem dist_exists_or : forall (X:Type) (P Q : X -> Prop),
(exists x, P x \/ Q x) <-> (exists x, P x) \/ (exists x, Q x).
Proof.
intros. split.
- intros H. destruct H. destruct H.
+ left. exists x. apply H.
+ right. exists x. apply H.
- intros H. destruct H.
+ destruct H. exists x. left. apply H.
+ destruct H. exists x. right. apply H.
Qed.
(** [] *)
(* ################################################################# *)
(** * Programming with Propositions *)
(** The logical connectives that we have seen provide a rich
vocabulary for defining complex propositions from simpler ones.
To illustrate, let's look at how to express the claim that an
element [x] occurs in a list [l]. Notice that this property has a
simple recursive structure:
- If [l] is the empty list, then [x] cannot occur on it, so the
property "[x] appears in [l]" is simply false.
- Otherwise, [l] has the form [x' :: l']. In this case, [x]
occurs in [l] if either it is equal to [x'] or it occurs in
[l']. *)
(** We can translate this directly into a straightforward Coq
function, [In]. (It can also be found in the Coq standard
library.) *)
Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
match l with
| [] => False
| x' :: l' => x' = x \/ In x l'
end.
(** When [In] is applied to a concrete list, it expands into a
concrete sequence of nested conjunctions. *)
Example In_example_1 : In 4 [3; 4; 5].
Proof.
simpl. right. left. reflexivity.
Qed.
Example In_example_2 :
forall n, In n [2; 4] ->
exists n', n = 2 * n'.
Proof.
simpl.
intros n [H | [H | []]].
- exists 1. rewrite <- H. reflexivity.
- exists 2. rewrite <- H. reflexivity.
Qed.
(** (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: *)
Lemma In_map :
forall (A B : Type) (f : A -> B) (l : list A) (x : A),
In x l ->
In (f x) (map f l).
Proof.
intros A B f l x.
induction l as [|x' l' IHl'].
- (* l = nil, contradiction *)
simpl. intros [].
- (* l = x' :: l' *)
simpl. intros [H | H].
+ rewrite H. left. reflexivity.
+ right. apply IHl'. apply H.
Qed.
(** This way of defining propositions, 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. *)
(** **** Exercise: 2 stars (In_map_iff) *)
Lemma In_map_iff :
forall (A B : Type) (f : A -> B) (l : list A) (y : B),
In y (map f l) <->
exists x, f x = y /\ In x l.
Proof.
split.
-induction l as [| h t IHl].
+ intros. inversion H.
+ intros. simpl. simpl in H. admit.
- admit.
Qed.
(** [] *)
(** **** Exercise: 2 stars (in_app_iff) *)
Lemma in_app_iff : forall A l l' (a:A),
In a (l++l') <-> In a l \/ In a l'.
Proof.
split.
- intros. induction l as [|h t IHl].
+ simpl in H. right. apply H.
+ simpl in H. simpl. destruct H.
* left. left. apply H.
* apply or_assoc. right. apply IHl. apply H.
- intros. induction l as [|h t IHl].
+ simpl. simpl in H. destruct H.
* inversion H.
* apply H.
+ simpl in H. simpl. apply or_assoc in H. destruct H.
* left. apply H.
* right. apply IHl in H. apply H.
Qed.
(** [] *)
(** **** Exercise: 3 stars (All) *)
(** Recall that functions returning propositions can be seen as
_properties_ of their arguments. For instance, if [P] has type
[nat -> Prop], then [P n] states that property [P] holds of [n].
Drawing inspiration from [In], write a recursive function [All]
stating that some property [P] holds of all elements of a list
[l]. To make sure your definition is correct, prove the [All_In]
lemma below. (Of course, your definition should _not_ just
restate the left-hand side of [All_In].) *)
Fixpoint All {T} (P : T -> Prop) (l : list T) : Prop :=
match l with
| [] => True
| h :: t => (P h) /\ (All P t)
end.
Lemma All_In :
forall T (P : T -> Prop) (l : list T),
(forall x, In x l -> P x) <->
All P l.
Proof.
intros. split.
- intros. induction l as [|x l' IHl].
+ simpl. apply I.
+ simpl. split.
* apply H. simpl. left. reflexivity.
* apply IHl. simpl in H. intros. apply H. right. apply H0.
- induction l as [|h l' IHl].
+ intros. simpl in H0. inversion H0.
+ intros. simpl in H,H0. destruct H0.
* destruct H. rewrite H0 in H. apply H.
* destruct H. apply IHl in H0.
{ apply H0. }
{ apply H1. }
Qed. (** [] *)
(** **** Exercise: 3 stars (combine_odd_even) *)
(** Complete the definition of the [combine_odd_even] function below.
It takes as arguments two properties of numbers, [Podd] and
[Peven], and it should return a property [P] such that [P n] is
equivalent to [Podd n] when [n] is odd and equivalent to [Peven n]
otherwise. *)
Definition combine_odd_even (Podd Peven : nat -> Prop) : nat -> Prop
(* REPLACE THIS LINE WITH := _your_definition_ . *) . Admitted.
(** To test your definition, prove the following facts: *)
Theorem combine_odd_even_intro :
forall (Podd Peven : nat -> Prop) (n : nat),
(oddb n = true -> Podd n) ->
(oddb n = false -> Peven n) ->
combine_odd_even Podd Peven n.
Proof.
(* FILL IN HERE *) Admitted.
Theorem combine_odd_even_elim_odd :
forall (Podd Peven : nat -> Prop) (n : nat),
combine_odd_even Podd Peven n ->
oddb n = true ->
Podd n.
Proof.
(* FILL IN HERE *) Admitted.
Theorem combine_odd_even_elim_even :
forall (Podd Peven : nat -> Prop) (n : nat),
combine_odd_even Podd Peven n ->
oddb n = false ->
Peven n.
Proof.
(* FILL IN HERE *) Admitted.
(** [] *)
(* ################################################################# *)
(** * Applying Theorems to Arguments *)
(** One feature of Coq that distinguishes it from many other proof
assistants is that it treats _proofs_ as first-class objects.
There is a great deal to be said about this, but it is not
necessary to understand it in detail in order to use Coq. This
section gives just a taste, while a deeper exploration can be
found in the optional chapters [ProofObjects] and
[IndPrinciples]. *)
(** We have seen that we can use the [Check] command to ask Coq to
print the type of an expression. We can also use [Check] to ask
what theorem a particular identifier refers to. *)
Check plus_comm.
(* ===> forall n m : nat, n + m = m + n *)
(** Coq prints the _statement_ of the [plus_comm] theorem in the same
way that it prints the _type_ of any term that we ask it to
[Check]. Why?
The reason is that the identifier [plus_comm] actually refers to a
_proof object_ -- a data structure that represents a logical
derivation establishing of the truth of the statement [forall n m
: nat, n + m = m + n]. The type of this object _is_ the statement
of the theorem that it is a proof of.
Intuitively, this makes sense because the statement of a theorem
tells us what we can use that theorem for, just as the type of a
computational object tells us what we can do with that object --
e.g., if we have a term of type [nat -> nat -> nat], we can give
it two [nat]s as arguments and get a [nat] back. Similarly, if we
have an object of type [n = m -> n + n = m + m] and we provide it
an "argument" of type [n = m], we can derive [n + n = m + m].
Operationally, this analogy goes even further: by applying a
theorem, as if it were a function, to hypotheses with matching
types, we can specialize its result without having to resort to
intermediate assertions. For example, suppose we wanted to prove
the following result: *)
Lemma plus_comm3 :
forall n m p, n + (m + p) = (p + m) + n.
(** It appears at first sight that we ought to be able to prove this
by rewriting with [plus_comm] twice to make the two sides match.
The problem, however, is that the second [rewrite] will undo the
effect of the first. *)
Proof.
intros n m p.
rewrite plus_comm.
rewrite plus_comm.
(* We are back where we started... *)
(** One simple way of fixing this problem, using only tools that we
already know, is to use [assert] to derive a specialized version
of [plus_comm] that can be used to rewrite exactly where we
want. *)
rewrite plus_comm.
assert (H : m + p = p + m).
{ rewrite plus_comm. reflexivity. }
rewrite H.
reflexivity.
Qed.
(** 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_take2 :
forall n m p, n + (m + p) = (p + m) + n.
Proof.
intros n m p.
rewrite plus_comm.
rewrite (plus_comm m).
reflexivity.
Qed.