forked from TurtlePU/Coq-2025
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLecture3_terse.v
2147 lines (1583 loc) · 63 KB
/
Lecture3_terse.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
(** * тактики: Больше тактик богу тактик! *)
Set Warnings "-notation-overridden,-parsing,-deprecated-hint-without-locality".
From Lectures Require Export Lecture2.
(* ################################################################# *)
(** * Тактика [apply] *)
(** Тактика [apply] полезна, когда какая-то из гипотез либо ранее
объявленная лемма в точности совпадает с целью: *)
Theorem silly1 : forall (n m : nat),
n = m ->
n = m.
Proof.
intros n m eq.
(** Здесь можно завершить с "[rewrite -> eq. reflexivity.]", как мы делали
раньше. Либо можно завершить в один шаг с помощью [apply]: *)
apply eq. Qed.
(** [apply] также работает с _обусловленными_ гипотезами: *)
Theorem silly2 : forall (n m o p : nat),
n = m ->
(n = m -> [n;o] = [m;p]) ->
[n;o] = [m;p].
Proof.
intros n m o p eq1 eq2.
apply eq2. apply eq1. Qed.
(** Обратите внимание, как Coq выбирает подходящие значения для
переменных, захваченных в гипотезе квантором [forall]: *)
Theorem silly2a : forall (n m : nat),
(n,n) = (m,m) ->
(forall (q r : nat), (q,q) = (r,r) -> [q] = [r]) ->
[n] = [m].
Proof.
intros n m eq1 eq2.
apply eq2. apply eq1. Qed.
(** Чтобы [apply] сработала, цель и гипотеза должны _полностью_
совпадать: *)
Theorem silly3 : forall (n m : nat),
n = m ->
m = n.
Proof.
intros n m H.
(** Здесь нельзя использовать [apply] напрямую... *)
Fail apply H.
(** но можно сначала применить тактику [symmetry], которая обменяет левую и
правую части равенства в цели. *)
symmetry. apply H. Qed.
(* ################################################################# *)
(** * Тактика [apply with] *)
(** Следующий простенький привер использует два переписывания подряд, чтобы
перейти от [[a;b]] к [[e;f]]. *)
Example trans_eq_example : forall (a b c d e f : nat),
[a;b] = [c;d] ->
[c;d] = [e;f] ->
[a;b] = [e;f].
Proof.
intros a b c d e f eq1 eq2.
rewrite -> eq1. apply eq2. Qed.
(** Так как это частый паттерн, давайте его вынесем в качестве леммы, которая
раз и навсегда устанавливает, что равенство транзитивно. *)
Theorem trans_eq : forall (X:Type) (x y z : X),
x = y -> y = z -> x = z.
Proof.
intros X x y z eq1 eq2. rewrite -> eq1. rewrite -> eq2.
reflexivity. Qed.
(** Применение этой леммы к примеру выше требует небольшого уточнения
при применении [apply]: *)
Example trans_eq_example' : forall (a b c d e f : nat),
[a;b] = [c;d] ->
[c;d] = [e;f] ->
[a;b] = [e;f].
Proof.
intros a b c d e f eq1 eq2.
Check trans_eq.
Fail apply trans_eq.
(** Просто [apply trans_eq] не сработает! А вот... *)
apply trans_eq with (y:=[c;d]).
(** поможет. *)
apply eq1. apply eq2. Qed.
(** [транзитивность] также доступна в качестве тактики. *)
Example trans_eq_example'' : forall (a b c d e f : nat),
[a;b] = [c;d] ->
[c;d] = [e;f] ->
[a;b] = [e;f].
Proof.
intros a b c d e f eq1 eq2.
transitivity [c;d].
apply eq1. apply eq2. Qed.
(* ################################################################# *)
(** * Тактики [injection] и [discriminate] *)
(** Конструкторы индуктивных типов _инъективны_ и _не пересекаются_.
Например, для [nat]...
- Если [S n = S m], то обязательно верно, что [n = m]
- [O] не равно [S n] ни для какого [n]
*)
(** Мы можем _доказать_ инъективность [S] с помощью функции [pred], определённой
в [Lecture1.v]. *)
Theorem S_injective : forall (n m : nat),
S n = S m ->
n = m.
Proof.
intros n m H1.
assert (H2: n = pred (S n)). { reflexivity. }
Print pred.
rewrite H2. rewrite H1. simpl. reflexivity.
Qed.
(** Для удобства, тактика [injection] позволяет нам пользоваться
инъективностью любого конструктора (не только [S]). *)
Theorem S_injective' : forall (n m : nat),
S n = S m ->
n = m.
Proof.
intros n m H.
injection H as Hnm. apply Hnm.
Qed.
(** А вот более интересный пример, который показывает, как [injection] можно
использовать, чтобы получить сразу несколько новых равенств. *)
Theorem injection_ex1 : forall (n m o : nat),
[n;m] = [o;o] ->
n = m.
Proof.
intros n m o H.
injection H as Hno Hmo.
transitivity o.
- apply Hno.
- symmetry. apply Hmo.
Qed.
(** Про инъективность понятно. Что насчёт отсутствия пересечений? *)
(** Два терма, начинающиеся с применения различных конструкторов (как то
[O] и [S] либо [true] и [false]) никогда не равны друг другу! *)
(** Тактика [discriminate] воплощает этот принцип: она применяется к гипотезе,
содержащей равенство между различными конструкторами (например,
[false = true]), и немедленно выполняет текущую цель. Парочка примеров: *)
Theorem discriminate_ex1 : forall (n m : nat),
false = true ->
n = m.
Proof.
intros n m contra. discriminate contra. Qed.
Theorem discriminate_ex2 : forall (n : nat),
S n = O ->
2 + 2 = 5.
Proof.
intros n contra. discriminate contra. Qed.
(** Эти примеры -- конкретные проявления логического принципа, известного как
_принцип взрыва_, который утверждает, что из противоречивого утверждения
следует что угодно (даже очевидно ложные вещи!). *)
(** В качестве более полезного примера, рассмотрим применение [discriminate] для
установления связи между двумя различными видами равенства ([=] и [=?]),
которые мы определяли для натуральных чисел. *)
Theorem eqb_0_l : forall n,
0 =? n = true -> n = 0.
Proof.
intros n.
destruct n as [| n'].
- (* n = 0 *)
intros H. reflexivity.
- (* n = S n' *)
simpl.
intros H. discriminate H.
Qed.
Compute (fun x => 1 + x).
(* QUIZ
Вспомним типы [rgb] и [color]:
Inductive rgb : Type := red | green | blue.
Inductive color : Type := black | white | primary (p: rgb).
Предположим, состояние доказательства на Coq выглядит как
x : rgb
y : rgb
H : primary x = primary y
============================
y = x
и мы применяем тактику [injection H as Hxy]. Что произойдёт?
(1) "No more subgoals."
(2) Тактика выбросит ошибку.
(3) Гипотеза [H] произведёт [Hxy : x = y].
(4) Ничего из вышеперечисленного.
*)
(* QUIZ
Положим, состояние доказательства на Coq выглядит как
x : bool
y : bool
H : negb x = negb y
============================
y = x
и мы применяем тактику [injection H as Hxy]. Что произойдёт?
(1) "No more subgoals."
(2) Тактика выбросит ошибку.
(3) Гипотеза [H] произведёт [Hxy : x = y].
(4) Ничего из вышеперечисленного.
*)
(* QUIZ
Теперь положим, что состояние доказательства на Coq выглядит как
x : nat
y : nat
H : x + 1 = y + 1
============================
y = x
и мы применяем тактику [injection H as Hxy]. Что произойдёт?
(1) "No more subgoals."
(2) Тактика выбросит ошибку.
(3) Гипотеза [H] произведёт [Hxy : x = y].
(4) Ничего из вышеперечисленного.
*)
(* QUIZ
Наконец, положим, что состояние доказательства на Coq выглядит как
x : nat
y : nat
H : 1 + x = 1 + y
============================
y = x
и мы применяем тактику [injection H as Hxy]. Что произойдёт?
(1) "No more subgoals."
(2) Тактика выбросит ошибку.
(3) Гипотеза [H] произведёт [Hxy : x = y].
(4) Ничего из вышеперечисленного.
*)
(** Инъективность конструкторов позволяет нам установить, что
[forall (n m : nat), S n = S m -> n = m]. Утверждение, обратное этой
импликации -- один из случаев более общего факта, верного как для
конструкторов, так и для функций. Он нам очень пригодится дальше: *)
Theorem f_equal : forall (A B : Type) (f: A -> B) (x y: A),
x = y -> f x = f y.
Proof. intros A B f x y eq. rewrite eq. reflexivity. Qed.
Theorem eq_implies_succ_equal : forall (n m : nat),
n = m -> S n = S m.
Proof. intros n m H. apply f_equal. apply H. Qed.
(** Coq также предоставляет [f_equal] в виде тактики. *)
Theorem eq_implies_succ_equal' : forall (n m : nat),
n = m -> S n = S m.
Proof. intros n m H. f_equal. apply H. Qed.
(* ################################################################# *)
(** * Применение тактик к гипотезам *)
(** У многих тактик доступна вариация вида "[... in ...]", которая
вместо цели применяется к гипотезе. *)
Theorem S_inj : forall (n m : nat) (b : bool),
((S n) =? (S m)) = b ->
(n =? m) = b.
Proof.
intros n m b H. simpl in H. apply H. Qed.
(** Обычный способ применения тактики [apply] -- это так называемый
"обратный ход рассуждений." По сути, пользуясь им, мы говорим "Мы пытаемся
доказать [X] и мы знаем [Y -> X], так что нам достаточно доказать [Y]."
А вот вариация [apply... in...] -- это, наоборот, "прямой ход рассуждений":
он говорит "Мы знаем, что [Y] и что [Y -> X], так что мы знаем [X]." *)
Theorem silly4 : forall (n m p q : nat),
(n = m -> p = q) ->
m = n ->
q = p.
Proof.
intros n m p q EQ H.
symmetry in H. apply EQ in H. symmetry in H.
apply H. Qed.
(* ################################################################# *)
(** * Уточнение гипотезы *)
(** Другая полезная для работы с гипотезами тактика называется [specialize].
По сути, это комбинация [assert] и [apply], но она достаточно часто
предоставляет до приятного аккуратный способ уточнить слишком общие
предположения. Она работает следующим образом:
Если [H] в текущем контексте это гипотеза с квантором, т.е. имеющая вид
[H : forall (x:T), P], тогда [specialize H with (x := e)] изменит [H] так,
что она теперь будет иметь тип [[x:=e]P], т.е., [P], где [x] заменили на
[e].
Например: *)
Theorem specialize_example: forall n,
(forall m, m*n = 0)
-> n = 0.
Proof.
intros n H.
specialize H with (m := 1).
rewrite mult_1_l in H.
apply H. Qed.
(** Используя [specialize] до [apply] даёт нам ещё один способ
проконтролировать, где и какую работу выполняет тактика [apply]. *)
Example trans_eq_example''' : forall (a b c d e f : nat),
[a;b] = [c;d] ->
[c;d] = [e;f] ->
[a;b] = [e;f].
Proof.
intros a b c d e f eq1 eq2.
specialize trans_eq with (y:=[c;d]) as H.
apply H.
apply eq1.
apply eq2. Qed.
(** Заметим:
- Мы можем [уточнять] факты и из глобального контекста, не только локальные
предположения.
- Клоза [as...] в конце сообщает [specialize], как в таком случае называть
новую гипотезу. *)
(* ################################################################# *)
(** * Варьирование предположения индукции *)
(** Вспомним функцию для удвоения натурального числа из главы
[Lecture1]: *)
Fixpoint double (n:nat) :=
match n with
| O => O
| S n' => S (S (double n'))
end.
(** Пусть мы хотим показать, что [double] инъективна (т.е.,
разные аргументы отображаются в разные значения). _Начинаем_ это
доказательство мы очень осторожно: *)
Theorem double_injective_FAILED : forall n m,
double n = double m ->
n = m.
Proof.
intros n m.
induction n as [| n' IHn'].
- (* n = O *) simpl. intros eq. destruct m as [| m'] eqn:E.
+ (* m = O *) reflexivity.
+ (* m = S m' *) discriminate eq.
- (* n = S n' *) intros eq. destruct m as [| m'] eqn:E.
+ (* m = O *) discriminate eq.
+ (* m = S m' *) f_equal.
(** В этой точке предположение индукции ([IHn']) _не_ утверждает [n' = m'] --
мешается лишняя [S] -- так что цель нам, увы, не доказать. *)
Abort.
(** Что пошло не так? *)
(** Попытка доказать утверждение индукцией по [n], когда [m] уже в контексте,
не работает, потому что так мы пытаемся доказать утверждение для
_произвольного_ [n], но лишь для некоторого _конкретного_ [m]. *)
(** Успешное доказательство [double_injective] оставляет [m] под квантором
вплоть до того момента, когда мы вызываем [индукцию] по [n]: *)
Theorem double_injective : forall n m,
double n = double m ->
n = m.
Proof.
intros n. induction n as [| n' IHn'].
- (* n = O *) simpl. intros m eq. destruct m as [| m'] eqn:E.
+ (* m = O *) reflexivity.
+ (* m = S m' *) discriminate eq.
- (* n = S n' *)
intros m eq.
destruct m as [| m'] eqn:E.
+ (* m = O *)
discriminate eq.
+ (* m = S m' *)
f_equal.
apply IHn'. simpl in eq. injection eq as goal. apply goal. Qed.
(** Урок, который нужно из этого вывести, следующий: при использовании индукции
нужно аккуратно следить за тем, чтобы не доказывать излишне конкретное
утверждение. Так, когда вы доказываете утверждение про переменные [n] и [m]
индукцией по [n], иногда принципиально важно, чтобы [m] оставалась под
квантором. *)
(** Следующая теорема, усиливающая связь между [=?] и [=], следует этому
же принципу. *)
Theorem eqb_true : forall n m,
n =? m = true -> n = m.
Proof.
induction n.
- destruct m.
+ reflexivity.
+ intros. discriminate H.
- destruct m.
+ intros. discriminate H.
+ simpl. intros. f_equal. apply IHn, H.
Qed.
(** Стратегия делать меньше [intros] перед [induction] для получения более
сильного предположения индукции работает не всегда; иногда переменные под
кванторами нужно _поменять местами_. Предположим, например, что мы хотим
доказать [double_injective] индукцией не по [n], а по [m]. *)
Theorem double_injective_take2_FAILED : forall n m,
double n = double m ->
n = m.
Proof.
intros n m. induction m as [| m' IHm'].
- (* m = O *) simpl. intros eq. destruct n as [| n'] eqn:E.
+ (* n = O *) reflexivity.
+ (* n = S n' *) discriminate eq.
- (* m = S m' *) intros eq. destruct n as [| n'] eqn:E.
+ (* n = O *) discriminate eq.
+ (* n = S n' *) f_equal.
(* Здесь мы застрянем точно так же, как раньше. *)
Abort.
(** Проблема в том, что, для использования [m], мы должны сначала ввести [n].
(А если мы скажем [induction m], ничего не вводя, Coq автоматически введёт
[n] за нас!) *)
(** What can we do about this? One possibility is to rewrite the
statement of the lemma so that [m] is quantified before [n]. This
works, but it's not nice: We don't want to have to twist the
statements of lemmas to fit the needs of a particular strategy for
proving them! Rather we want to state them in the clearest and
most natural way. *)
(** Вместо этого мы можем сначала ввести все подкванторные переменные, а
затем _заново обобщить_ по некоторым из них. Тактика [generalize dependent]
делает именно это. *)
Theorem double_injective_take2 : forall n m,
double n = double m ->
n = m.
Proof.
intros n m.
(* И [n], и [m] уже в контексте. *)
generalize dependent n.
(* Now [n] is back in the goal and we can do induction on
[m] and get a sufficiently general IH. *)
induction m as [| m' IHm'].
- (* m = O *) simpl. intros n eq. destruct n as [| n'] eqn:E.
+ (* n = O *) reflexivity.
+ (* n = S n' *) discriminate eq.
- (* m = S m' *) intros n eq. destruct n as [| n'] eqn:E.
+ (* n = O *) discriminate eq.
+ (* n = S n' *) f_equal.
apply IHm'. injection eq as goal. apply goal. Qed.
(* ################################################################# *)
(** * Unfolding Definitions *)
(** It sometimes happens that we need to manually unfold a name that
has been introduced by a [Definition] so that we can manipulate
the expression it stands for.
For example, if we define... *)
Definition square n := n * n.
(** ...and try to prove a simple fact about [square]... *)
Lemma square_mult : forall n m, square (n * m) = square n * square m.
Proof.
intros n m.
simpl.
(** ...we appear to be stuck: [simpl] doesn't simplify anything, and
since we haven't proved any other facts about [square], there is
nothing we can [apply] or [rewrite] with. *)
(** To make progress, we can manually [unfold] the definition of
[square]: *)
unfold square.
(** Now we have plenty to work with: both sides of the equality are
expressions involving multiplication, and we have lots of facts
about multiplication at our disposal. In particular, we know that
it is commutative and associative, and from these it is not hard
to finish the proof. *)
rewrite mult_assoc.
assert (H : n * m * n = n * n * m).
{ rewrite mul_comm. apply mult_assoc. }
rewrite H. rewrite mult_assoc. reflexivity.
Qed.
(** At this point, a bit deeper discussion of unfolding and
simplification is in order.
We already have observed that tactics like [simpl], [reflexivity],
and [apply] will often unfold the definitions of functions
automatically when this allows them to make progress. For
example, if we define [foo m] to be the constant [5]... *)
Definition foo (x: nat) := 5.
(** .... then the [simpl] in the following proof (or the
[reflexivity], if we omit the [simpl]) will unfold [foo m] to
[(fun x => 5) m] and further simplify this expression to just
[5]. *)
Fact silly_fact_1 : forall m, foo m + 1 = foo (m + 1) + 1.
Proof.
intros m.
simpl.
reflexivity.
Qed.
(** But this automatic unfolding is somewhat conservative. For
example, if we define a slightly more complicated function
involving a pattern match... *)
Definition bar x :=
match x with
| O => 5
| S _ => 5
end.
(** ...then the analogous proof will get stuck: *)
Fact silly_fact_2_FAILED : forall m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
simpl. (* Does nothing! *)
Abort.
(** The reason that [simpl] doesn't make progress here is that it
notices that, after tentatively unfolding [bar m], it is left with
a match whose scrutinee, [m], is a variable, so the [match] cannot
be simplified further. It is not smart enough to notice that the
two branches of the [match] are identical, so it gives up on
unfolding [bar m] and leaves it alone.
Similarly, tentatively unfolding [bar (m+1)] leaves a [match]
whose scrutinee is a function application (that cannot itself be
simplified, even after unfolding the definition of [+]), so
[simpl] leaves it alone. *)
(** There are now two ways make progress.
(1) Use [destruct m] to break the proof into two cases: *)
Fact silly_fact_2 : forall m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
destruct m eqn:E.
- simpl. reflexivity.
- simpl. reflexivity.
Qed.
(** This approach works, but it depends on our recognizing that the
[match] hidden inside [bar] is what was preventing us from making
progress. *)
(** (2) Explicitly tell Coq to unfold [bar]. *)
Fact silly_fact_2' : forall m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
unfold bar.
(** Now it is apparent that we are stuck on the [match] expressions on
both sides of the [=], and we can use [destruct] to finish the
proof without thinking so hard. *)
destruct m eqn:E.
- reflexivity.
- reflexivity.
Qed.
(* ################################################################# *)
(** * Using [destruct] on Compound Expressions *)
(** The [destruct] tactic can be used on expressions as well as
variables: *)
Definition sillyfun (n : nat) : bool :=
if n =? 3 then false
else if n =? 5 then false
else false.
Theorem sillyfun_false : forall (n : nat),
sillyfun n = false.
Proof.
intros n. unfold sillyfun.
destruct (n =? 3) eqn:E1.
- (* n =? 3 = true *) reflexivity.
- (* n =? 3 = false *) destruct (n =? 5) eqn:E2.
+ (* n =? 5 = true *) reflexivity.
+ (* n =? 5 = false *) reflexivity. Qed.
(** The [eqn:] part of the [destruct] tactic is optional; although
we've chosen to include it most of the time, for the sake of
documentation, it can often be omitted without harm.
However, when [destruct]ing compound expressions, the information
recorded by the [eqn:] can actually be critical: if we leave it
out, then [destruct] can erase information we need to complete a
proof. *)
Definition sillyfun1 (n : nat) : bool :=
if n =? 3 then true
else if n =? 5 then true
else false.
Theorem sillyfun1_odd_FAILED : forall (n : nat),
sillyfun1 n = true ->
odd n = true.
Proof.
intros n eq. unfold sillyfun1 in eq.
destruct (n =? 3).
(* stuck... *)
Abort.
(** Adding the [eqn:] qualifier saves this information so we
can use it. *)
Theorem sillyfun1_odd : forall (n : nat),
sillyfun1 n = true ->
odd n = true.
Proof.
intros n eq. unfold sillyfun1 in eq.
destruct (n =? 3) eqn:Heqe3.
- (* e3 = true *) apply eqb_true in Heqe3.
rewrite -> Heqe3. reflexivity.
- (* e3 = false *)
destruct (n =? 5) eqn:Heqe5.
+ (* e5 = true *)
apply eqb_true in Heqe5.
rewrite -> Heqe5. reflexivity.
+ (* e5 = false *) discriminate eq. Qed.
(* ################################################################# *)
(** * Micro Sermon *)
(** Mindless proof-hacking is a terrible temptation...
Try to resist!
*)
(* ################################################################# *)
(** * Logic: Logic in Coq *)
Set Warnings "-notation-overridden,-parsing".
Set Warnings "-deprecated-hint-without-locality".
Require Nat.
(** So far, we have seen...
- _propositions_: mathematical statements, so far only of 3 kinds:
- equality propositions ([e1 = e2])
- implications ([P -> Q])
- quantified propositions ([forall x, P])
- _proofs_: ways of presenting evidence for the truth of a
proposition
In this chapter we will introduce several more flavors of both
propositions and proofs. *)
(** Like everything in Coq, well-formed propositions have a _type_: *)
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
a different thing! *)
Check 2 = 2 : Prop.
Check 3 = 2 : Prop.
Check forall n : nat, n = 2 : Prop.
(** So far, we've seen one primary place where propositions can appear:
in [Theorem] (and [Lemma] and [Example]) declarations. *)
Theorem plus_2_2_is_4 :
2 + 2 = 4.
Proof. reflexivity. Qed.
(** Propositions are first-class entities in Coq, though. For
example, we can name them: *)
Definition plus_claim : Prop := 2 + 2 = 4.
Check plus_claim : Prop.
Theorem plus_claim_is_true :
plus_claim.
Proof. reflexivity. Qed.
(** We can also write _parameterized_ propositions -- that is,
functions that take arguments of some type and return a
proposition. *)
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) : Prop :=
forall x y : A, f x = f y -> x = y.
Lemma succ_inj : injective S.
Proof.
intros x y H. injection H as H1. apply H1.
Qed.
(** The familiar equality operator [=] is a (binary) function that returns
a [Prop].
The expression [n = m] is syntactic sugar for [eq n m] (defined in
Coq's standard library using the [Notation] mechanism).
Because [eq] can be used with elements of any type, it is also
polymorphic: *)
Check @eq : forall A : Type, A -> A -> Prop.
(* QUIZ
What is the type of the following expression?
pred (S O) = O
(1) [Prop]
(2) [nat->Prop]
(3) [forall n:nat, Prop]
(4) [nat->nat]
(5) Not typeable
*)
Check (pred (S O) = O) : Prop.
(* QUIZ
What is the type of the following expression?
forall n:nat, pred (S n) = n
(1) [Prop]
(2) [nat->Prop]
(3) [forall n:nat, Prop]
(4) [nat->nat]
(5) Not typeable
*)
Check (forall n:nat, pred (S n) = n) : Prop.
(* QUIZ
What is the type of the following expression?
forall n:nat, S (pred n) = n
(1) [Prop]
(2) [nat->Prop]
(3) [nat->nat]
(4) Not typeable
*)
Check (forall n:nat, S (pred n) = n) : Prop.
(* QUIZ
What is the type of the following expression?
forall n:nat, S (pred n)
(1) [Prop]
(2) [nat->Prop]
(3) [nat->nat]
(4) Not typeable
*)
Fail Check (forall n:nat, S (pred n)).
(* The command has indeed failed with message:
In environment
n : nat
The term "(S (pred n))" has type "nat" which should be Set, Prop or Type. *)
(* QUIZ
What is the type of the following expression?
fun n:nat => S (pred n)
(1) [Prop]
(2) [nat->Prop]
(3) [nat->nat]
(4) Not typeable
*)
Check (fun n:nat => pred (S n)) : nat -> nat.
(* QUIZ
What is the type of the following expression?
fun n:nat => S (pred n) = n
(1) [Prop]
(2) [nat->Prop]
(3) [nat->nat]
(4) Not typeable
*)
Check (fun n:nat => pred (S n) = n) : nat -> Prop.
(* QUIZ
Which of the following is _not_ a proposition?
(1) [3 + 2 = 4]
(2) [3 + 2 = 5]
(3) [3 + 2 =? 5]
(4) [((3+2) =? 4) = false]
(5) [forall n, (((3+2) =? n) = true) -> n = 5]
(6) All of these are propositions
*)
Check 3 + 2 =? 5 : bool.
Fail Definition bad : Prop := 3 + 2 =? 5.
(* The command has indeed failed with message: *)
(* The term "3 + 2 =? 5" has type "bool" while it is expected to have
type "Prop". *)
(* ################################################################# *)
(** * Logical Connectives *)
(* ================================================================= *)
(** ** Conjunction *)
(** The _conjunction_, or _logical and_, of propositions [A] and [B] is
written [A /\ B]; it represents 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. This will generate
two subgoals, one for each part of the statement: *)
Proof.
split.
- (* 3 + 4 = 7 *) reflexivity.
- (* 2 * 2 = 4 *) reflexivity.
Qed.
(** For any propositions [A] and [B], if we assume that [A] is true and
that [B] is true, we can conclude that [A /\ B] is also true. The Coq
library provides a function [conj] that does this. *)
Check @conj : forall A B : Prop, A -> B -> A /\ B.
(** we can [apply conj] to achieve the same effect as [split]. *)
Example plus_is_O :
forall n m : nat, n + m = 0 -> n = 0 /\ m = 0.
Proof.
intros * H.
assert (HL : forall x y, x + y = 0 -> x = 0).
{ intros. destruct x. reflexivity. discriminate H0. }
split.
- apply HL with (y := m), H.
- rewrite add_comm in H.
apply HL with (y := n), H.
Qed.
(** So much for proving conjunctive statements. To go in the other
direction -- i.e., to _use_ a conjunctive hypothesis to help prove
something else -- we employ the [destruct] tactic. *)
Lemma and_example2 :
forall n m : nat, n = 0 /\ m = 0 -> n + m = 0.
Proof.
intros * [Hn Hm]. rewrite Hn, Hm. reflexivity.
Qed.
(** As usual, we can also destruct [H] right 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 also have 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.