-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathcontra.v
864 lines (742 loc) · 48.4 KB
/
contra.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
(* mathcomp analysis (c) 2017 Inria and AIST. License: CeCILL-C. *)
From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
From mathcomp Require Import boolp.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
(**md**************************************************************************)
(* # Contraposition *)
(* *)
(* This file provides tactics to reason by contraposition and contradiction. *)
(* *)
(* ## Tactics *)
(* ``` *)
(* assume_not == add a goal negation assumption. The tactic also works for *)
(* goals in Type, simplifies the added assumption, and *)
(* exposes its top-level constructive content. *)
(* absurd_not == proof by contradiction. Same as assume_not, but the goal is *)
(* erased and replaced by False. *)
(* Caveat: absurd_not cannot be used as a move/ view because *)
(* its conclusion is indeterminate. The more general notP can *)
(* be used instead. *)
(* contra == proof by contraposition. Change a goal of the form *)
(* assumption -> conclusion to ~ conclusion -> ~ assumption. *)
(* As with assume_not, contra allows both assumption and *)
(* conclusion to be in Type, simplifies the negation of both *)
(* assumption and conclusion, and exposes the constructive *)
(* contents of the negated conclusion. *)
(* The contra tactic also supports a limited form of the ':' *)
(* discharge pseudo tactical, whereby contra: <d-items> means *)
(* move: <d-items>; contra. *)
(* The only <d-items> allowed are one term, possibly preceded *)
(* by a clear switch. *)
(* absurd == proof by contradiction. The defective form of the tactic *)
(* simply replaces the entire goal with False (just as the Ltac *)
(* exfalso), leaving the user to derive a contradiction from *)
(* the assumptions. *)
(* The ':' form absurd: <d-items> replaces the goal with the *)
(* negation of the (single) <d-item> (as with contra:, a clear *)
(* switch is also allowed. *)
(* Finally the Ltac absurd term form is also supported. *)
(* ``` *)
(******************************************************************************)
(** Hiding module for the internal definitions and lemmas used by the tactics
defined here. *)
Module Internals.
(**md**************************************************************************)
(* A wrapper for view lemmas with an indeterminate conclusion (of the form *)
(* forall ... T ..., pattern -> T), and for which the intended view pattern *)
(* may fail to match some assumptions. This wrapper ensures that such views *)
(* are only used in the forward direction (as in move/), and only with the *)
(* appropriate move_viewP hint, preventing its application to an arbitrary *)
(* assumption A by the instatiation to A -> T' of its indeterminate *)
(* conclusion T. This is similar to the implies wrapper, except move_viewP *)
(* is *NOT* declared as a coercion---it must be used explicitly to apply the *)
(* view manually to an assumption (as in, move_viewP my_view some_assumption).*)
(******************************************************************************)
Variant move_view S T := MoveView of S -> T.
Definition move_viewP {S T} mv : S -> T := let: MoveView v := mv in v.
Hint View for move/ move_viewP|2.
(**md**************************************************************************)
(* ## Type-level equivalence *)
(******************************************************************************)
Variant equivT S T := EquivT of S -> T & T -> S.
Definition equivT_refl S : equivT S S := EquivT id id.
Definition equivT_transl {S T U} : equivT S T -> equivT S U -> equivT T U :=
fun (st : equivT S T) (su : equivT S U) =>
let: EquivT S_T T_S := st in
let: EquivT S_U U_S := su in
EquivT (S_U \o T_S) (S_T \o U_S).
Definition equivT_sym {S T} : equivT S T -> equivT T S :=
equivT_transl^~ (equivT_refl S).
Definition equivT_trans {S T U} : equivT S T -> equivT T U -> equivT S U :=
equivT_transl \o equivT_sym.
Definition equivT_transr {S T U} eqST : equivT U S -> equivT U T :=
equivT_trans^~ eqST.
Definition equivT_Prop (P Q : Prop) : (equivT P Q) <-> (equivT P Q).
Proof. split; destruct 1; split; assumption. Defined.
Definition equivT_LR {S T} (eq : equivT S T) : S -> T :=
let: EquivT S_T _ := eq in S_T.
Definition equivT_RL {S T} (eq : equivT S T) : T -> S :=
let: EquivT _ T_S := eq in T_S.
Hint View for move/ equivT_LR|2 equivT_RL|2.
Hint View for apply/ equivT_RL|2 equivT_LR|2.
(**md**************************************************************************)
(* A generic Forall "constructor" for the Gallina forall quantifier, i.e., *)
(* ``` *)
(* \Forall x, P := Forall (fun x => P) := forall x, P. *)
(* ``` *)
(* The main use of Forall is to apply congruence to a forall equality: *)
(* ``` *)
(* congr1 Forall : forall P Q, P = Q -> Forall P = Forall Q. *)
(* ``` *)
(* in particular in a classical setting with function extensionality, where *)
(* we can have (forall x, P x = Q x) -> (forall x, P x) = (forall x, Q x). *)
(* *)
(* We use a forallSort structure to factor the ad hoc PTS product formation *)
(* rules; forallSort is keyed on the type of the entire forall expression, or *)
(* (up to subsumption) the type of the forall body---this is always a sort. *)
(* *)
(* This implementation has two important limitations: *)
(* 1. It cannot handle the SProp sort and its typing rules. However, its *)
(* main application is extensionality, which is not compatible with *)
(* SProp because an (A : SProp) -> B "function" is not a generic *)
(* (A : Type) -> B function as SProp is not included in Type. *)
(* 2. The Forall constructor can't be inserted by a straightforward *)
(* unfold (as in, rewrite -[forall x, _]/(Forall _)) because of the *)
(* way Coq unification handles Type constraints. The ForallI tactic *)
(* mitigates this issue, but there are additional issues with its *)
(* implementation---see below. *)
(******************************************************************************)
Structure forallSort A :=
ForallSort {forall_sort :> Type; _ : (A -> forall_sort) -> forall_sort}.
Notation mkForallSort A S := (@ForallSort A S (fun T => forall x, T x)).
Polymorphic Definition TypeForall (S := Type) (A : S) := mkForallSort A S.
Canonical TypeForall.
Canonical PropForall A := mkForallSort A Prop.
(* This is just a special case of TypeForall, but it provides a projection *)
(* for the Set sort "constant". *)
Canonical SetForall (A : Set) := mkForallSort A Set.
Definition Forall {A} {S : forallSort A} :=
let: ForallSort _ F := S return (A -> S) -> S in F.
Notation "\Forall x .. z , T" :=
(Forall (fun x => .. (Forall (fun z => T)) ..))
(at level 200, x binder, z binder, T at level 200,
format "'[hv' '\Forall' '[' x .. z , ']' '/ ' T ']'") : type_scope.
(* The ForallI implementation has to work around several Coq 8.12 issues: *)
(* - Coq unification defers Type constraints so we must ensure the type *)
(* constraint for the forall term F is processed, and the resulting *)
(* sort unified with the forall_sort projection _BEFORE_ F is unified *)
(* with a Forall _ pattern, because the inferred forallSort structure *)
(* determines the actual shape of that pattern. This is done by passing *)
(* F to erefl, then constraining the type of erefl to Forall _ = _. Note *)
(* that putting a redundant F on the right hand side would break due to *)
(* incomplete handling of subtyping. *)
(* - ssr rewrite and Coq replace do not handle universe constraints. *)
(* and rewrite does not handle subsumption of the redex type. This means *)
(* we cannot use rewrite, replace or fold, and must resort to primitive *)
(* equality destruction. *)
(* - ssr case: and set do not recognize ssrpatternarg parameters, so we *)
(* must rely on ssrmatching.ssrpattern. *)
Tactic Notation "ForallI" ssrpatternarg(pat) :=
let F := fresh "F" in ssrmatching.ssrpattern pat => F;
case: F / (@erefl _ F : Forall _ = _).
Tactic Notation "ForallI" := ForallI (forall x, _).
(**md**************************************************************************)
(* We define specialized copies of the wrapped structure of ssrfun for Prop *)
(* and Type, as we need more than two alternative rules (indeed, 3 for Prop *)
(* and 4 for Type). We need separate copies for Prop and Type as universe *)
(* polymorphism cannot instantiate Type with Prop. *)
(******************************************************************************)
Structure wrappedProp := WrapProp {unwrap_Prop :> Prop}.
Definition wrap4Prop := WrapProp.
Definition wrap3Prop := wrap4Prop.
Definition wrap2Prop := wrap3Prop.
Canonical wrap1Prop P := wrap2Prop P.
Polymorphic Structure wrappedType@{i} := WrapType {unwrap_Type :> Type@{i}}.
Polymorphic Definition wrap4Type@{i} := WrapType@{i}.
Polymorphic Definition wrap3Type@{i} := wrap4Type@{i}.
Polymorphic Definition wrap2Type@{i} := wrap3Type@{i}.
Polymorphic Definition wrap1Type@{i} (T : Type@{i}) := wrap2Type T.
Canonical wrap1Type.
Lemma generic_forall_extensionality {A} {S : forallSort A} {P Q : A -> S} :
P =1 Q -> Forall P = Forall Q.
Proof. by move/funext->. Qed.
(**md**************************************************************************)
(* A set of tools (tactics, views, and rewrite rules) to facilitate the *)
(* handling of classical negation. The core functionality of these tools is *)
(* implemented by three sets of canonical structures that provide for the *)
(* simplification of negation statements (e.g., using de Morgan laws), the *)
(* conversion from constructive statements in Type to purely logical ones in *)
(* Prop (equivalently, expansion rules for the statement inhabited T), and *)
(* conversely extraction of constructive contents from logical statements. *)
(* *)
(* Except for bool predicates and operators, all definitions are treated *)
(* transparently when matching statements for either simplification or *)
(* conversion; this is achieved by using the wrapper telescope pattern, first *)
(* delegating the matching of specific logical connectives, predicates, or *)
(* type constructors to an auxiliary structure that *FAILS* to match unknown *)
(* operators, thus triggers the expansion of defined constants. If this *)
(* ultimately fails then the wrapper is expanded, and the primary structure *)
(* instance for the expanded wrapper provides an alternative default rule: *)
(* not simplifying ~ P, not expanding inhabited T, or not extracting any *)
(* contents from a proposition P, respectively. *)
(* *)
(* Additional rules, for intermediate wrapper instances, are used to handle *)
(* forall statements (for which canonical instances are not yet supported), *)
(* as well as addiitonal simplifications, such as inhabited P = P :> Prop. *)
(* *)
(* Finally various tertiary structures are used to match deeper patterns, *)
(* such as bounded forall statements of the form forall x, P x -> Q x, or *)
(* inequalites x != y (i.e., is_true (~~ (x == y))). As mentioned above, *)
(* tertiary rules for bool subexpressions do not try to expand definitions, *)
(* as this would lead to the undesirable expansion of some standard *)
(* definitions. This is simply achieved by *NOT* using the wrapper telescope *)
(* pattern, and just having a default instance alongside those for specific *)
(* predicates and connectives. *)
(******************************************************************************)
(**md**************************************************************************)
(* The negatedProp structure provides simplification of the Prop negation *)
(* (~ _) for standard connectives and predicates. The instances below cover *)
(* the pervasive and ssrbool Prop connectives, decidable equality, as well as *)
(* bool propositions (i.e., the is_true predicate), together with a few bool *)
(* connectives and predicates: negation ~~, equality ==, and nat <= and <. *)
(* Others can be added (e.g., Order.le/lt) by declaring appropriate instances *)
(* of bool_negation and bool_affirmation, while other Prop connectives and *)
(* predicates can be added by declaring instances of proper_negatedProp. *)
(******************************************************************************)
(**md**************************************************************************)
(* The implementation follows the wrapper telescope pattern outlined above: *)
(* negatedProp instances match on the wrappedProp wrapper to try three *)
(* generic matching rules, in succession: *)
(* - Rule 1: match a specific connective or predicate with an instance of the *)
(* properNegatedProp secondary structure, expanding definitions *)
(* if needed, but failing if no proper match is found. *)
(* - Rule 2: match a forall statement (including (T : Type) -> P statements). *)
(* - Rule 3: match any Prop but return the trivial simplification. *)
(* The simplified proposition is returned as a projection parameter nP rather *)
(* than a Structure member, so that applying the corresponding views or *)
(* rewrite rules doesn't expose the inferred structures; properNegatedProp *)
(* does similarly. Also, negatedProp similarly returns a 'trivial' bool flag *)
(* that is set when Rule 3 is used, but this is actually used in the reverse *)
(* direction: views notP and rewrite rule notE force trivial := false, thus *)
(* excluding trivial instances. *)
(******************************************************************************)
Structure negatedProp (trivial : bool) nP :=
NegatedProp {negated_Prop :> wrappedProp; _ : (~ negated_Prop) = nP}.
Structure properNegatedProp nP := ProperNegatedProp {
proper_negated_Prop :> Prop; _ : (~ proper_negated_Prop) = nP}.
Local Notation nProp t nP P := (unwrap_Prop (@negated_Prop t nP P)).
Local Notation nPred t nP P x := (nProp t (nP x) (P x)).
Local Notation pnProp nP P := (@proper_negated_Prop nP P).
(**md**************************************************************************)
(* User views and rewrite rules. The plain versions (notP, notE and notI) do *)
(* not match trivial instances; lax_XXX versions allow them. In addition, *)
(* the negation introduction rewrite rule notI does not match forall or -> *)
(* statements---lax_notI must be used for these. *)
(******************************************************************************)
Lemma lax_notE {t nP} P : (~ nProp t nP P) = nP. Proof. by case: P. Qed.
Lemma lax_notP {t nP P} : ~ nProp t nP P -> nP. Proof. by rewrite lax_notE. Qed.
Definition lax_notI {t nP} P : nProp t nP P = (~ nP) := canRL notK (lax_notE P).
Definition notE {nP} P : (~ nProp false nP P) = nP := lax_notE P.
Definition notP {nP P} := MoveView (@lax_notP false nP P).
Fact proper_nPropP nP P : (~ pnProp nP P) = nP. Proof. by case: P. Qed.
Definition notI {nP} P : pnProp nP P = ~ nP := canRL notK (proper_nPropP P).
(** Rule 1: proper negation simplification, delegated to properNegatedProp. *)
Canonical proper_nProp nP P :=
@NegatedProp false nP (wrap1Prop (pnProp nP P)) (proper_nPropP P).
(** Rule 2: forall_nProp is defined below as it uses exists_nProp. *)
(** Rule 3: trivial negation. *)
Canonical trivial_nProp P := @NegatedProp true (~ P) (wrap3Prop P) erefl.
(** properNegatedProp instances. *)
Canonical True_nProp := @ProperNegatedProp False True notB.1.
Canonical False_nProp := @ProperNegatedProp True False notB.2.
Canonical not_nProp P := @ProperNegatedProp P (~ P) (notK P).
Fact and_nPropP P tQ nQ Q : (~ (P /\ nProp tQ nQ Q)) = (P -> nQ).
Proof. by rewrite -implypN lax_notE. Qed.
Canonical and_nProp P tQ nQ Q :=
ProperNegatedProp (@and_nPropP P tQ nQ Q).
Fact and3_nPropP P Q tR nR R : (~ [/\ P, Q & nProp tR nR R]) = (P -> Q -> nR).
Proof. by hnf; rewrite and3E notE. Qed.
Canonical and3_nProp P Q tR nR R :=
ProperNegatedProp (@and3_nPropP P Q tR nR R).
Fact and4_nPropP P Q R tS nS S :
(~ [/\ P, Q, R & nProp tS nS S]) = (P -> Q -> R -> nS).
Proof. by hnf; rewrite and4E notE. Qed.
Canonical and4_nProp P Q R tS nS S :=
ProperNegatedProp (@and4_nPropP P Q R tS nS S).
Fact and5_nPropP P Q R S tT nT T :
(~ [/\ P, Q, R, S & nProp tT nT T]) = (P -> Q -> R -> S -> nT).
Proof. by hnf; rewrite and5E notE. Qed.
Canonical and5_nProp P Q R S tT nT T :=
ProperNegatedProp (@and5_nPropP P Q R S tT nT T).
Fact or_nPropP tP nP P tQ nQ Q :
(~ (nProp tP nP P \/ nProp tQ nQ Q)) = (nP /\ nQ).
Proof. by rewrite not_orE !lax_notE. Qed.
Canonical or_nProp tP nP P tQ nQ Q :=
ProperNegatedProp (@or_nPropP tP nP P tQ nQ Q).
Fact or3_nPropP tP nP P tQ nQ Q tR nR R :
(~ [\/ nProp tP nP P, nProp tQ nQ Q | nProp tR nR R]) = [/\ nP, nQ & nR].
Proof. by rewrite or3E notE and3E. Qed.
Canonical or3_nProp tP nP P tQ nQ Q tR nR R :=
ProperNegatedProp (@or3_nPropP tP nP P tQ nQ Q tR nR R).
Fact or4_nPropP tP nP P tQ nQ Q tR nR R tS nS S :
(~ [\/ nProp tP nP P, nProp tQ nQ Q, nProp tR nR R | nProp tS nS S])
= [/\ nP, nQ, nR & nS].
Proof. by rewrite or4E notE and4E. Qed.
Canonical or4_nProp tP nP P tQ nQ Q tR nR R tS nS S :=
ProperNegatedProp (@or4_nPropP tP nP P tQ nQ Q tR nR R tS nS S).
(**md**************************************************************************)
(* The andRHS tertiary structure used to simplify (~ (P -> False)) to P, *)
(* both here for the imply_nProp instance and for bounded_forall_nProp below. *)
(* Because the andRHS instances match the Prop RETURNED by negatedProp they *)
(* do not need to expand definitions, hence do not need to use the wrapper *)
(* telescope pattern. *)
(******************************************************************************)
Notation and_def binary P Q PQ := (PQ = if binary then P /\ Q else Q)%type.
Structure andRHS binary P Q PQ :=
AndRHS {and_RHS :> Prop; _ : (P /\ and_RHS) = PQ; _ : and_def binary P Q PQ}.
Canonical unary_and_rhs P := @AndRHS false P P P True (andB.1.2 P) erefl.
Canonical binary_and_rhs P Q := @AndRHS true P Q (P /\ Q) Q erefl erefl.
Fact imply_nPropP b P nQ PnQ tR (nR : andRHS b P nQ PnQ) R :
(~ (P -> nProp tR nR R)) = PnQ.
Proof. by rewrite -orNp {R}lax_notE; case: nR. Qed.
Canonical imply_nProp b P nQ PnQ tR nR R :=
ProperNegatedProp (@imply_nPropP b P nQ PnQ tR nR R).
Fact exists_nPropP A tP nP P :
(~ exists x : A, nPred tP nP P x) = (forall x : A, nP x).
Proof.
eqProp=> [nEP x | AnP [x]]; last by rewrite -/(~ _) lax_notE.
by rewrite -(lax_notE (P x)) => Px; case: nEP; exists x.
Qed.
Canonical exists_nProp A tP nP P :=
ProperNegatedProp (@exists_nPropP A tP nP P).
Fact exists2_nPropP A P tQ nQ Q :
(~ exists2 x : A, P x & nPred tQ nQ Q x) = (forall x : A, P x -> nQ x).
Proof. by rewrite exists2E notE. Qed.
Canonical exists2_nProp A P tQ nQ Q :=
ProperNegatedProp (@exists2_nPropP A P tQ nQ Q).
Fact inhabited_nPropP T : (~ inhabited T) = (T -> False).
Proof. by rewrite inhabitedE notE. Qed.
Canonical inhabited_nProp T := ProperNegatedProp (inhabited_nPropP T).
(**md**************************************************************************)
(* Rule 2: forall negation, including (T : Type) -> P statements. *)
(* *)
(* We use tertiary structures to recognize bounded foralls and simplify, *)
(* e.g., ~ forall x, P -> Q to exists2 x, P & ~ Q, or even exists x, P when *)
(* Q := False (as above for imply). *)
(* *)
(* As forall_body_nProp and forall_body_proper_nProp are telescopes *)
(* over negatedProp and properNegatedProp, respectively, their instances *)
(* match instances declared above without the need to expand definitions, *)
(* hence do not need to use the wrapper telescope idiom. *)
(******************************************************************************)
Structure negatedForallBody bounded P nQ tR nR := NegatedForallBody {
negated_forall_body :> negatedProp tR nR; _ : and_def bounded P nQ nR}.
Structure properNegatedForallBody b P nQ nR := ProperNegatedForallBody {
proper_negated_forall_body :> properNegatedProp nR; _ : and_def b P nQ nR}.
Notation nBody b P nQ t nR x := (negatedForallBody b (P x) (nQ x) t (nR x)).
(**md**************************************************************************)
(* The explicit argument to fun_if is a workaround for a bug in the Coq *)
(* unification code that prevents default instances from ever matching match *)
(* constructs. Furthermore rewriting with ifE would not work here, because *)
(* the if_expr definition would be expanded by the eta expansion needed to *)
(* match the exists_nProp rule. *)
(******************************************************************************)
Fact forall_nPropP A b P nQ tR nR (R : forall x, nBody b P nQ tR nR x) :
(~ forall x : A, R x) = if b then exists2 x, P x & nQ x else exists x, nQ x.
Proof.
rewrite exists2E -(fun_if (fun P => exists x, idfun P x)) notI /=; congr not.
apply/generic_forall_extensionality=> x; rewrite if_arg lax_notI.
by case: (R x) => _ <-.
Qed.
Canonical forall_nProp A b P nQ tR nR (R : forall x, nBody b P nQ tR nR x) :=
@NegatedProp false _ (wrap2Prop (forall x : A, R x)) (forall_nPropP R).
Fact proper_nBodyP b P nQ nR :
properNegatedForallBody b P nQ nR -> and_def b P nQ nR.
Proof. by case. Qed.
Canonical proper_nBody b P nQ nR R :=
let def_nR := @proper_nBodyP b P nQ nR R in
@NegatedForallBody b P nQ false nR (proper_nProp R) def_nR.
Canonical nonproper_nBody tP nP P :=
@NegatedForallBody false True nP tP nP P erefl.
Fact andRHS_def b P Q PQ : andRHS b P Q PQ -> and_def b P Q PQ.
Proof. by case. Qed.
Canonical bounded_nBody b P nQ PnQ tR nR R :=
ProperNegatedForallBody (@imply_nProp b P nQ PnQ tR nR R) (andRHS_def nR).
Canonical unbounded_nBody nQ Q :=
@ProperNegatedForallBody false True nQ nQ Q erefl.
(**md**************************************************************************)
(* The properNegatedProp instance that handles boolean statements. We use *)
(* two tertiary structures to handle positive and negative boolean statements *)
(* so that the contra tactic below will mostly subsume the collection of *)
(* contraXX lemmas in ssrbool and eqtype. *)
(* *)
(* We only match manifest ~~ connectives, the true and false constants, and *)
(* the ==, <=%N, and <%N predicates. In particular we do not use de Morgan *)
(* laws to push boolean negation into connectives, as we did above for Prop *)
(* connectives. It will be up to the user to use rewriting to put the negated *)
(* statement in its desired shape. *)
(******************************************************************************)
Structure negatedBool nP :=
NegatedBool {negated_bool :> bool; _ : (~ negated_bool) = nP}.
Structure positedBool P :=
PositedBool {posited_bool :> bool; _ : is_true posited_bool = P}.
Local Fact is_true_nPropP nP (b : negatedBool nP) : (~ b) = nP.
Proof. by case: b. Qed.
Canonical is_true_nProp nP b := ProperNegatedProp (@is_true_nPropP nP b).
Local Fact true_negP : (~ true) = False. Proof. by eqProp. Qed.
Local Fact true_posP : (true : Prop) = True. Proof. by eqProp. Qed.
Local Fact false_negP : (~ false) = True. Proof. by eqProp. Qed.
Local Fact false_posP : (false : Prop) = False. Proof. by eqProp. Qed.
Canonical true_neg := NegatedBool true_negP.
Canonical true_pos := PositedBool true_posP.
Canonical false_neg := NegatedBool false_negP.
Canonical false_pos := PositedBool false_posP.
Local Fact id_negP (b : bool) : (~ b) = ~~ b. Proof. exact/reflect_eq/negP. Qed.
Canonical id_neg b := NegatedBool (id_negP b).
Canonical id_pos (b : bool) := @PositedBool b b erefl.
Local Fact negb_negP P (b : positedBool P) : (~ ~~ b) = P.
Proof. by rewrite (reflect_eq negP) negbK; case: b. Qed.
Canonical negb_neg P b := NegatedBool (@negb_negP P b).
Local Fact negb_posP nP (b : negatedBool nP) : (~~ b = nP :> Prop).
Proof. by rewrite -(reflect_eq negP) notE. Qed.
Canonical negb_pos nP b := PositedBool (@negb_posP nP b).
(**md**************************************************************************)
(* We use a tertiary structure to handle the negation of nat comparisons, and *)
(* simplify ~ m <= n to n < m, and ~ m < n to n <= m. As m < n is merely *)
(* notation for m.+1 <= n, we need to dispatch on the left hand side of the *)
(* comparison to perform the latter simplification. *)
(******************************************************************************)
Structure negatedLeqLHS n lt_nm :=
NegatedLeqLHS {negated_leq_LHS :> nat; _ : (n < negated_leq_LHS) = lt_nm}.
Canonical neg_ltn_LHS n m := @NegatedLeqLHS n (n <= m) m.+1 erefl.
Canonical neg_leq_LHS n m := @NegatedLeqLHS n (n < m) m erefl.
Local Fact leq_negP n lt_nm (m : negatedLeqLHS n lt_nm) : (~ m <= n) = lt_nm.
Proof. by rewrite notE -ltnNge; case: m => /= m ->. Qed.
Canonical leq_neg n lt_nm m := NegatedBool (@leq_negP n lt_nm m).
(**md**************************************************************************)
(* We use two tertiary structures to simplify negation of boolean constant *)
(* and decidable equalities, simplifying b <> true to ~~ b, b <> false to b, *)
(* x <> y to x != y, and ~ x != y to x = y. We do need to use the wrapper *)
(* telescope pattern here, as we want to simplify instances of x <> y when y *)
(* evaluates to true or false. Since we only need two rules (true/false RHS *)
(* or generic eqType RHS) we can use the generic wrapped type from ssrfun. *)
(* The actual matching of the true and false RHS is delegated to a fourth *)
(* level bool_eq_negation_rhs structure. Finally observe that the ~ x != y to *)
(* x = y simplification can be handled by a bool_affirmation instance. *)
(******************************************************************************)
Structure neqRHS nP T x :=
NeqRHS {neq_RHS :> wrapped T; _ : (x <> unwrap neq_RHS) = nP}.
Structure boolNeqRHS nP (x : bool) :=
BoolNeqRHS {bool_neq_RHS; _ : (x <> bool_neq_RHS) = nP}.
Local Fact eq_nPropP nP T x (y : neqRHS nP x) : (x <> unwrap y :> T) = nP.
Proof. by case: y. Qed.
Canonical eq_nProp nP T x y := ProperNegatedProp (@eq_nPropP nP T x y).
Local Fact bool_neqP nP x y : (x <> @bool_neq_RHS nP x y) = nP.
Proof. by case: y. Qed.
Canonical bool_neq nP x y := @NeqRHS nP bool x (wrap _) (@bool_neqP nP x y).
Canonical true_neq nP b := BoolNeqRHS (@is_true_nPropP nP b).
Local Fact false_neqP P (b : positedBool P) : (b <> false :> bool) = P.
Proof. by move: b => [] [] /= <-; exact/propext. Qed.
Canonical false_neq P b := BoolNeqRHS (@false_neqP P b).
Local Fact eqType_neqP (T : eqType) (x y : T) : (x <> y) = (x != y).
Proof. by rewrite (reflect_eq eqP) (reflect_eq negP). Qed.
Canonical eqType_neq (T : eqType) x y :=
@NeqRHS (x != y) T x (Wrap y) (eqType_neqP x y).
Local Fact eq_op_posP (T : eqType) x y : (x == y :> T : Prop) = (x = y).
Proof. exact/esym/reflect_eq/eqP. Qed.
Canonical eq_op_pos T x y := PositedBool (@eq_op_posP T x y).
(**md**************************************************************************)
(* The witnessedType structure provides conversion between Type and Prop in *)
(* goals; the conversion is mostly used in the Type-to-Prop direction, e.g., *)
(* as a preprocessing step preceding proof by contradiction (see absurd_not *)
(* below), but the Prop-to-Type direction is required for contraposition. *)
(* *)
(* Thus witnessedType associates to a type T a "witness" proposition P *)
(* equivalent to the existence of an x of type T. As in a `{classical_logic} *)
(* context inhabited T is such a proposition, witnessedType can be understood *)
(* as providing simplification for inhabited T, much like negatedProp *)
(* provides simplification for ~ P for standard connectives and predicates. *)
(******************************************************************************)
(**md**************************************************************************)
(* Similarly to negatedProp, witnessedType returns the witness proposition *)
(* via a projection argument P, but does not need to signal "trivial" *)
(* instances as the default value for P is nontrivial (namely, inhabited T), *)
(* while the "trivial" case where P = T is actually desireable and handled *)
(* by an extra top-priority rule. *)
(******************************************************************************)
Structure witnessedType P := WitnessedType {
witnessed_Type :> wrappedType; _ : inhabited witnessed_Type = P}.
Structure properWitnessedType P := ProperWitnessedType {
proper_witnessed_Type :> Type; _ : inhabited proper_witnessed_Type = P}.
Local Notation wType P T := (unwrap_Type (@witnessed_Type P T)).
Local Notation wTycon P T x := (wType (P x) (T x)).
(* User interface lemmas. *)
Lemma witnessedType_intro {P : Prop} T : P -> wType P T.
Proof. by case: T => /= T <- /inhabited_witness. Qed.
Local Coercion witnessedType_intro : witnessedType >-> Funclass.
Lemma witnessedType_elim {P} T : wType P T -> P.
Proof. by case: T => /= T <-. Qed.
Local Notation wTypeP := witnessedType_elim.
(* Helper lemma and tactic. *)
Local Fact eq_inhabited T (P : Prop) : (T -> P) -> (P -> T) -> inhabited T = P.
Proof. by move=> T_P P_T; eqProp=> [[/T_P] | /P_T]. Qed.
Ltac eqInh := apply: eq_inhabited.
(** Rule 1: Prop goals are left as is. *)
Canonical Prop_wType P :=
@WitnessedType P (wrap1Type P) (eq_inhabited (@id P) id).
(** Rule 2: Specific type constructors (sigs, sums, and pairs) are delegated
to the secondary properWitnessedType structure. *)
Lemma proper_wTypeP P (T : properWitnessedType P) : inhabited T = P.
Proof. by case: T. Qed.
Canonical proper_wType P T :=
@WitnessedType P (wrap2Type _) (@proper_wTypeP P T).
(** Rule 3: Forall (and -> as a special case). *)
Local Fact forall_wTypeP A P T :
inhabited (forall x : A, wTycon P T x) = (forall x : A, P x) .
Proof. by do [eqInh=> allP x; have:= allP x] => [/wTypeP | /T]. Qed.
Canonical forall_wType A P T :=
@WitnessedType _ (wrap3Type _) (@forall_wTypeP A P T).
(** Rule 4: Default to inhabited if all else fails. *)
Canonical inhabited_wType T := @WitnessedType (inhabited T) (wrap4Type T) erefl.
(** Specific proper_witnessedType instances. *)
Local Fact void_wTypeP : inhabited void = False. Proof. by eqInh. Qed.
Canonical void_wType := ProperWitnessedType void_wTypeP.
Local Fact unit_wTypeP : inhabited unit = True. Proof. by eqInh. Qed.
Canonical unit_wType := ProperWitnessedType unit_wTypeP.
Local Fact pair_wTypeP P Q S T : inhabited (wType P S * wType Q T) = (P /\ Q).
Proof. by eqInh=> [[/wTypeP-isP /wTypeP] | [/S-x /T]]. Qed.
Canonical pair_wType P Q S T := ProperWitnessedType (@pair_wTypeP P Q S T).
Local Fact sum_wTypeP P Q S T : inhabited (wType P S + wType Q T) = (P \/ Q).
Proof. by eqInh=> [[] /wTypeP | /decide_or[/S | /T]]; by [left | right]. Qed.
Canonical sum_wType P Q S T := ProperWitnessedType (@sum_wTypeP P Q S T).
Local Fact sumbool_wTypeP P Q : inhabited ({P} + {Q}) = (P \/ Q).
Proof. by eqInh=> [[] | /decide_or[]]; by [left | right]. Qed.
Canonical sumbool_wType P Q := ProperWitnessedType (@sumbool_wTypeP P Q).
Local Fact sumor_wTypeP P Q T : inhabited (wType P T + {Q}) = (P \/ Q).
Proof. by eqInh=> [[/wTypeP|] | /decide_or[/T|]]; by [left | right]. Qed.
Canonical sumor_wType P Q T := ProperWitnessedType (@sumor_wTypeP P Q T).
Local Fact sig1_wTypeP T P : inhabited {x : T | P x} = (exists x : T, P x).
Proof. by eqInh=> [[x Px] | /cid//]; exists x. Qed.
Canonical sig1_wType T P := ProperWitnessedType (@sig1_wTypeP T P).
Local Fact sig2_wTypeP T P Q :
inhabited {x : T | P x & Q x} = exists2 x : T, P x & Q x.
Proof. by eqInh=> [[x Px Qx] | /cid2//]; exists x. Qed.
Canonical sig2_wType T P Q := ProperWitnessedType (@sig2_wTypeP T P Q).
Local Fact sigT_wTypeP A P T :
inhabited {x : A & wTycon P T x} = (exists x : A, P x).
Proof. by eqInh=> [[x /wTypeP] | /cid[x /T]]; exists x. Qed.
Canonical sigT_wType A P T := ProperWitnessedType (@sigT_wTypeP A P T).
Local Fact sigT2_wTypeP A P Q S T :
inhabited {x : A & wTycon P S x & wTycon Q T x} = (exists2 x : A, P x & Q x).
Proof. by eqInh=> [[x /wTypeP-Px /wTypeP] | /cid2[x /S-y /T]]; exists x. Qed.
Canonical sigT2_wType A P Q S T :=
ProperWitnessedType (@sigT2_wTypeP A P Q S T).
(**md**************************************************************************)
(* The witnessProp structure provides for conversion of some Prop *)
(* assumptions to Type values with some constructive contents, e.g., convert *)
(* a P \/ Q assumption to a {P} + {Q} sumbool value. This is not the same as *)
(* the forward direction of witnessedType, because instances here match the *)
(* Prop statement: witness_Prop find a T such that P -> T while witnessedType *)
(* finds a P such that P -> T (and T -> P for the converse direction). *)
(******************************************************************************)
(**md**************************************************************************)
(* The implementation follows the wrapper telescope pattern similarly to *)
(* negatedProp, with three rules, one for Prop constructors with proper *)
(* constructive contents, one for forall propositions (also with proper *)
(* constructive contents) and one default rule that just returns P : Prop as *)
(* is (thus, with no other contents except the provability of P). *)
(* *)
(* The witnessProp structure also uses projection parameters to return the *)
(* inferred Type T together with a bool 'trivial' flag that is set when the *)
(* trivial rule is used. Here, however, this flag is used in both directions: *)
(* the 'witness' view forces it to false to prevent trivial instances, but *)
(* the flag is also used to fine tune the choice of T, selecting between *)
(* sum, sumor, and sumbool, between sig and sigT, and sig2 and sigT2. This *)
(* relies on the fact that the tactic engine will eagerly iota reduce the *)
(* returned type, so that the user will never see the conditionals specified *)
(* in the proper_witness_Prop instances. *)
(* *)
(* However, it would not be possible to construct the specialised types *)
(* for trivial witnesses (e.g., {P} + {Q}) using the types returned by *)
(* witnessProp instances, since thes are in Type, and the information that *)
(* they are actully in Prop has been lost. This is solved by returning an *)
(* additional Prop P0 that is a copy of the matched Prop P when *)
(* trivial = true. (We put P0 = True when trivial = false, as we only need to *)
(* ensure P -> P0.) *)
(* *)
(* Caveat: although P0 should in principle be the last parameter of *)
(* witness_Prop, and we use this order for the wProp and wPred projector *)
(* local notation, it is important to put P0 _BEFORE_ T, to circumvent an *)
(* incompleteness in Coq's implementation of higher-order pattern unification *)
(* that would cause the trivial rule to fail for the body of an exists. *)
(* In such a case the rule needs to unify (1) ?P0 x ~ ?P and (2) ?T x ~ ?P *)
(* for some type A some x : A in the context of ?P, but not ?P0 nor ?T. This *)
(* succeeds easily if (1) is performed before (2), setting ?P := ?P0 x and *)
(* ?T := ?P0, but if (2) is attempted first Coq tries to perform ?P := ?T x, *)
(* which fails Type/Prop universe constraints, and then fails outright, *)
(* instead of using pattern unification to solve (2) as ?P := ?Q x, ?T := ?Q *)
(* for a fresh ?Q : A -> Prop. *)
(******************************************************************************)
Structure witnessProp (trivial : bool) (P0 : Prop) (T : Type) :=
WitnessProp {witness_Prop :> wrappedProp; _ : witness_Prop -> T * P0}.
Structure properWitnessProp T :=
ProperWitnessProp {proper_witness_Prop :> Prop; _ : proper_witness_Prop -> T}.
Local Notation wProp t T P0 P := (unwrap_Prop (@witness_Prop t P0 T P)).
Local Notation wPred t T P0 P x := (wProp t (T x) (P0 x) (P x)).
Local Fact wPropP t T P0 P : wProp t T P0 P -> T * P0. Proof. by case: P. Qed.
Lemma lax_witness {t T P0 P} : move_view (wProp t T P0 P) T.
Proof. by split=> /wPropP[]. Qed.
Definition witness {T P0 P} := @lax_witness false T P0 P.
(** Rule 1: proper instances (except forall), delegated to an auxiliary
structures. *)
Local Fact proper_wPropP T P : wrap1Prop (@proper_witness_Prop T P) -> T * True.
Proof. by case: P => _ P_T {}/P_T. Qed.
Canonical proper_wProp T P := WitnessProp false (@proper_wPropP T P).
(** Rule 2: forall types (including implication); as only proper instances are
allowed, we set trivial = false for the recursive body instance. *)
Local Fact forall_wPropP A T P0 P :
wrap2Prop (forall x : A, wPred false T P0 P x) -> (forall x, T x) * True.
Proof. by move=> P_A; split=> // x; have /witness := P_A x. Qed.
Canonical forall_wProp A T P0 P := WitnessProp false (@forall_wPropP A T P0 P).
(** Rule 3: trivial (proof) self-witness. *)
Canonical trivial_wProp P :=
WitnessProp true (fun p : wrap3Prop P => (p, p) : P * P).
(** Specific proper_witnesss_Prop instances. *)
Canonical inhabited_wProp T := ProperWitnessProp (@inhabited_witness T).
(**md**************************************************************************)
(* Conjunctions P /\ Q are a little delicate to handle, as we should not *)
(* produce a proper instance (and thus fail) if neither P nor Q is proper. *)
(* We use a tertiary structure for this : nand_bool b, which has instances *)
(* only for booleans b0 such that ~~ (b0 && b). We allow the witness_Prop *)
(* instance for P to return an arbitrary 'trivial' flag s, but then force the *)
(* 'trivial' flag for Q to be an instance of nand_bool s. *)
(******************************************************************************)
Structure nandBool b := NandBool {nand_bool :> bool; _ : ~~ (nand_bool && b)}.
Canonical nand_false_bool b := @NandBool b false isT.
Canonical nand_true_bool := @NandBool false true isT.
Local Fact and_wPropP s S P0 P (t : nandBool s) T Q0 Q :
wProp s S P0 P /\ wProp t T Q0 Q -> S * T.
Proof. by case=> /lax_witness-x /lax_witness. Qed.
Canonical and_wProp s S P0 P t T Q0 Q :=
ProperWitnessProp (@and_wPropP s S P0 P t T Q0 Q).
(* The first : Type cast ensures the return type of the inner 'if' is not *)
(* incorrectly set to 'Set', while the second merely ensures the S + T *)
(* notation is resolved correctly). *)
Local Fact or_wPropP s S P0 P t T Q0 Q :
wProp s S P0 P \/ wProp t T Q0 Q ->
if t then if s then {P0} + {Q0} : Type else S + {Q0} else S + T : Type.
Proof.
by case: s t => -[] in P Q *; (case/decide_or=> /wPropP[]; [left | right]).
Qed.
Canonical or_wProp s S P0 P t T Q0 Q :=
ProperWitnessProp (@or_wPropP s S P0 P t T Q0 Q).
Local Fact exists_wPropP A t T P0 P :
(exists x : A, wPred t T P0 P x) -> if t then {x | P0 x} else {x & T x}.
Proof. by case/cid => x /wPropP[]; case t; exists x. Qed.
Canonical exists_wProp A t T P0 P :=
ProperWitnessProp (@exists_wPropP A t T P0 P).
(* Note the expanded expression for st = s && t, which will be reduced to *)
(* true or false by iota reduction when s and t are known. *)
Local Fact exists2_wPropP A s S P0 P t T Q0 Q (st := if s then t else false) :
(exists2 x : A, wPred s S P0 P x & wPred t T Q0 Q x) ->
if st then {x | P0 x & Q0 x} else {x : A & S x & T x}.
Proof. by case/cid2=> x /wPropP[P0x y] /wPropP[]; case: ifP; exists x. Qed.
Canonical exists2_wProp A s S P0 P t T Q0 Q :=
ProperWitnessProp (@exists2_wPropP A s S P0 P t T Q0 Q).
(**md**************************************************************************)
(* ## User lemmas and tactics for proof by contradiction and contraposition. *)
(******************************************************************************)
(**md**************************************************************************)
(* Helper lemmas: *)
(* - push_goal_copy makes a copy of the goal that can then be matched with *)
(* witnessedType and negatedProp instances to generate a contradiction *)
(* assuption, without disturbing the original form of the goal. *)
(* - assume_not_with turns the copy generated by push_identity into an *)
(* equivalent negative assumption, which can then be simplified using the *)
(* lax_notP and lax_witness views. *)
(* - absurd and absurdW replace the goal with False; absurdW does this under *)
(* an assumption, and is used to weaken proof-by-assuming-negation to *)
(* proof-by-contradiction. *)
(* - contra_Type converts an arbitrary function goal (with assumption and *)
(* conclusion in Type) to an equivalent contrapositive Prop implication. *)
(* - contra_notP simplifies a contrapositive ~ Q -> ~ P goal using *)
(* negatedProp instances. *)
(******************************************************************************)
Local Fact push_goal_copy {T} : ((T -> T) -> T) -> T. Proof. exact. Qed.
Local Fact assume_not_with {R P T} : (~ P -> R) -> (wType P T -> R) -> R.
Proof. by move=> nP_T T_R; have [/T|] := asboolP P. Qed.
Local Fact absurdW {S T} : (S -> False) -> S -> T. Proof. by []. Qed.
Local Fact contra_Type {P Q S T} : (~ Q -> ~ P) -> wType P S -> wType Q T.
Proof. by rewrite implyNN => P_Q /wTypeP/P_Q/T. Qed.
Local Fact contra_notP tP tQ (nP nQ : Prop) P Q :
(nP -> nQ) -> (~ nProp tP nP P -> ~ nProp tQ nQ Q).
Proof. by rewrite 2!lax_notE. Qed.
End Internals.
Import Internals.
Definition notP := @Internals.notP.
Hint View for move/ move_viewP|2.
Hint View for move/ Internals.equivT_LR|2 Internals.equivT_RL|2.
Hint View for apply/ Internals.equivT_RL|2 Internals.equivT_LR|2.
Export (canonicals) Internals.
(**md**************************************************************************)
(* Lemma and tactic assume_not: add a goal negation assumption. The tactic *)
(* also works for goals in Type, simplifies the added assumption, and *)
(* exposes its top-level constructive content. *)
(******************************************************************************)
Lemma assume_not {P} : (~ P -> P) -> P. Proof. by rewrite implyNp orB. Qed.
Ltac assume_not :=
apply: Internals.push_goal_copy; apply: Internals.assume_not_with
=> /Internals.lax_notP-/Internals.lax_witness.
(**md**************************************************************************)
(* Lemma and tactic absurd_not: proof by contradiction. Same as assume_not, *)
(* but the goal is erased and replaced by False. *)
(* Caveat: absurd_not cannot be used as a move/ view because its conclusion *)
(* is indeterminate. The more general notP defined above can be used instead. *)
(******************************************************************************)
Lemma absurd_not {P} : (~ P -> False) -> P. Proof. by move/Internals.notP. Qed.
Ltac absurd_not := assume_not; apply: Internals.absurdW.
(**md**************************************************************************)
(* Tactic contra: proof by contraposition. Assume the negation of the goal *)
(* conclusion, and prove the negation of a given assumption. The defective *)
(* form contra (which can also be written contrapose) expects the assumption *)
(* to be pushed on the goal which thus has the form assumption -> conclusion. *)
(* *)
(* As with assume_not, contra allows both assumption and conclusion to be *)
(* in Type, simplifies the negation of both assumption and conclusion, and *)
(* exposes the constructive contents of the negated conclusion. *)
(* *)
(* The contra tactic also supports a limited form of the ':' discharge *)
(* pseudo tactical, whereby contra: <d-items> means move: <d-items>; contra. *)
(* The only <d-items> allowed are one term, possibly preceded by a clear *)
(* switch. *)
(******************************************************************************)
Ltac contrapose :=
apply: Internals.contra_Type;
apply: Internals.contra_notP => /Internals.lax_witness.
Tactic Notation "contra" := contrapose.
Tactic Notation "contra" ":" constr(H) := move: (H); contra.
Tactic Notation "contra" ":" ident(H) := move: H; contra.
Tactic Notation "contra" ":" "{" hyp_list(Hs) "}" constr(H) :=
contra: (H); clear Hs.
Tactic Notation "contra" ":" "{" hyp_list(Hs) "}" ident(H) :=
contra: H; clear Hs.
Tactic Notation "contra" ":" "{" "-" "}" constr(H) := contra: (H).
(**md**************************************************************************)
(* Lemma and tactic absurd: proof by contradiction. The defective form of the *)
(* lemma simply replaces the entire goal with False (just as the Ltac *)
(* exfalso), leaving the user to derive a contradiction from the assumptions. *)
(* The ':' form absurd: <d-items> replaces the goal with the negation of the *)
(* (single) <d-item> (as with contra:, a clear switch is also allowed. *)
(* Finally the Ltac absurd term form is also supported. *)
(******************************************************************************)
Lemma absurd T : False -> T. Proof. by []. Qed.
Tactic Notation (at level 0) "absurd" := apply absurd.
Tactic Notation (at level 0) "absurd" constr(P) := have []: ~ P.
Tactic Notation "absurd" ":" constr(H) := absurd; contra: (H) => _.
Tactic Notation "absurd" ":" ident(H) := absurd; contra: H => _.
Tactic Notation "absurd" ":" "{" hyp_list(Hs) "}" constr(H) :=
absurd: (H) => _; clear Hs.
Tactic Notation "absurd" ":" "{" hyp_list(Hs) "}" ident(H) :=
absurd: H => _; clear Hs.