@@ -19,7 +19,9 @@ will see:
19
19
20
20
> import Basics
21
21
22
- import Poly
22
+ \todo[inline]{If we \idr{import Poly } here, the pair sugar, among other things,
23
+ will start messing things up, so we just copypaste the necessary definitions for
24
+ now}
23
25
24
26
\todo[inline]{Describe \idr{Pruviloj} and \idr{%runElab}}
25
27
@@ -31,9 +33,6 @@ will see:
31
33
32
34
> %language ElabReflection
33
35
34
- %hide Poly .MumbleGrumble.A
35
- %hide Poly .MumbleGrumble.B
36
-
37
36
38
37
== The \idr{exact} Tactic
39
38
@@ -42,11 +41,17 @@ as some hypothesis in the context or some previously proved lemma.
42
41
43
42
> silly1 : (n, m, o, p : Nat) -> (n = m) -> [n,o] = [n,p] -> [n,o] = [m,p]
44
43
45
- Here, we could prove this with
44
+ Here, we could prove this with rewrites :
46
45
47
46
> silly1 n m o p eq1 eq2 = rewrite eq2 in
48
47
> rewrite eq1 in Refl
49
48
49
+ or the dependent pattern matching:
50
+
51
+ ```idris
52
+ silly1 m m p p Refl Refl = Refl
53
+ ```
54
+
50
55
as we have done several times before. We can achieve the same effect by a series
51
56
of tactic applications, using \idr{exact} instead of the
52
57
\idr{rewrite}+\idr{Refl} combination:
@@ -160,11 +165,15 @@ tactic, which switches the left and right sides of an equality in the goal.
160
165
(_Hint_: You can use \idr{exact} with previously defined lemmas , not just
161
166
hypotheses in the context . Remember that `:search` is your friend.)
162
167
163
- rev_exercise1 : (l, l' : List Nat ) -> l = rev l' -> l' = rev l
164
- rev_exercise1 = ?remove_me1 -- %runElab rev_exercise1_tac
165
- where
166
- rev_exercise1_tac : Elab ()
167
- rev_exercise1_tac = ?rev_exercise1_tac_rhs
168
+ > rev : (l : List x ) -> List x
169
+ > rev [] = []
170
+ > rev (h::t) = (rev t ) ++ [h]
171
+
172
+ > rev_exercise1 : (l, l' : List Nat ) -> l = rev l' -> l' = rev l
173
+ > rev_exercise1 = ?remove_me1 -- %runElab rev_exercise1_tac
174
+ > where
175
+ > rev_exercise1_tac : Elab ()
176
+ > rev_exercise1_tac = ?rev_exercise1_tac_rhs
168
177
169
178
$\square$
170
179
@@ -189,12 +198,17 @@ The following silly example uses two rewrites in a row to get from `[a,b]` to
189
198
> trans_eq_example a b c d e f eq1 eq2 = rewrite eq1 in
190
199
> rewrite eq2 in Refl
191
200
201
+ Note that this can also be proven with dependent pattern matching:
202
+
203
+ ```idris
204
+ trans_eq_example a b a b a b Refl Refl = Refl
205
+ ```
206
+
192
207
Since this is a common pattern , we might like to pull it out as a lemma
193
208
recording, once and for all , the fact that equality is transitive .
194
209
195
210
> trans_eq : (n, m, o : x) -> n = m -> m = o -> n = o
196
- > trans_eq n m o eq1 eq2 = rewrite eq1 in
197
- > rewrite eq2 in Refl
211
+ > trans_eq n n n Refl Refl = Refl
198
212
199
213
(This lemma already exists in Idris' stdlib under the name of \idr{trans}.)
200
214
@@ -302,6 +316,12 @@ derived at once.
302
316
303
317
\todo[inline]{Make prettier and contribute to Pruviloj ?}
304
318
319
+ > getTTType : Raw -> Elab TT
320
+ > getTTType r = do
321
+ > env <- getEnv
322
+ > rty <- check env r
323
+ > pure $ snd rty
324
+
305
325
> symmetryIn : Raw -> TTName -> Elab ()
306
326
> symmetryIn t n = do
307
327
> tt <- getTTType t
@@ -315,12 +335,6 @@ derived at once.
315
335
> tsymty <- forget ! (getTTType tsym)
316
336
> letbind n tsymty tsym
317
337
> _ => fail [TermPart tt, TextPart " is not an equality" ]
318
- > where
319
- > getTTType : Raw -> Elab TT
320
- > getTTType r = do
321
- > env <- getEnv
322
- > rty <- check env r
323
- > pure $ snd rty
324
338
325
339
\ todo[inline]{Works quite fast in Elab shell but hangs the compiler}
326
340
@@ -398,13 +412,16 @@ things!
398
412
\ todo[inline]{How to show impossible cases from Elab ? }
399
413
400
414
> inversion_ex4 : (n : Nat ) -> S n = Z -> 2 + 2 = 5
401
- > inversion_ex4 n prf = absurd $ SIsNotZ prf
415
+ > -- we need "sym" because Prelude.Nat only disproves "Z = S n" for us
416
+ > inversion_ex4 n prf = absurd $ sym prf
417
+
418
+ \ todo[inline]{Remove if https : //github.com/idris-lang/Idris-dev/pull/3925 is merged}
402
419
403
- > FalseNotTrue : False = True -> Void
404
- > FalseNotTrue Refl impossible
420
+ > Uninhabited ( False = True ) where
421
+ > uninhabited Refl impossible
405
422
406
423
> inversion_ex5 : (n, m : Nat ) -> False = True -> [n] = [m]
407
- > inversion_ex5 n m prf = absurd $ FalseNotTrue prf
424
+ > inversion_ex5 n m prf = absurd prf
408
425
409
426
If you find the principle of explosion confusing, remember that these proofs are
410
427
not actually showing that the conclusion of the statement holds. Rather , they
@@ -450,7 +467,7 @@ general fact about both constructors and functions, which we will find useful in
450
467
a few places below :
451
468
452
469
> f_equal : (f : a -> b) -> (x, y : a) -> x = y -> f x = f y
453
- > f_equal f x y eq = rewrite eq in Refl
470
+ > f_equal f x x Refl = Refl
454
471
455
472
(This is called \ idr{cong} in Idris' stdlib. )
456
473
@@ -474,25 +491,50 @@ in H performs simplification in the hypothesis named \idr{h} in the context.
474
491
> | _ => fail []
475
492
> exact $ Var eq
476
493
477
- \ todo[inline]{Write \ idr{applyIn} and reformulate the example as it's trivial in
478
- Idris }
494
+ \ todo[inline]{Contribute to Pruviloj }
495
+
496
+ > applyIn : Raw -> Raw -> TTName -> Elab ()
497
+ > applyIn f x n = do
498
+ > ftt <- getTTType f
499
+ > case ftt of
500
+ > `(~ xty -> ~ yty) => do
501
+ > let fx = RApp f x
502
+ > fxty <- forget ! (getTTType fx)
503
+ > letbind n fxty fx
504
+ > _ => fail [TermPart ftt, TextPart " is not a function" ]
505
+
506
+ \ todo[inline]{Edit }
479
507
480
- Similarly , apply L in H matches some conditional statement L (of the form L1 ->
481
- L2 , say) against a hypothesis H in the context. However , unlike ordinary apply
482
- (which rewrites a goal matching L2 into a subgoal L1 ), apply L in H matches H
483
- against L1 and , if successful, replaces it with L2 .
508
+ Similarly , \ idr{applyIn l h} matches some conditional statement \ idr{l} (of the
509
+ form \ idr{l1 -> l2}, say) against a hypothesis \ idr{h} in the context. However ,
510
+ unlike ordinary \ idr{exact} (which rewrites a goal matching \ idr{l2} into a
511
+ subgoal \ idr{l1}), \ idr{applyIn l h n} matches \ idr{h} against \ idr{l1} and , if
512
+ successful, binds the result \ idr{l2} to \ idr{n}.
484
513
485
- In other words , apply L in H gives us a form of " forward reasoning" : from L1 ->
486
- L2 and a hypothesis matching L1 , it produces a hypothesis matching L2 . By
487
- contrast, apply L is " backward reasoning" : it says that if we know L1 -> L2 and we
488
- are trying to prove L2 , it suffices to prove L1 .
514
+ In other words , \ idr{applyIn l h} gives us a form of " forward reasoning" : from
515
+ \ idr{l1 -> l2} and a hypothesis matching \ idr{l1}, it produces a hypothesis
516
+ matching \ idr{l2}. By contrast, \ idr{exact l} is " backward reasoning" : it says
517
+ that if we know \ idr{l1-> l2} and we are trying to prove \ idr{l2}, it suffices to
518
+ prove \ idr{l1}.
489
519
490
520
Here is a variant of a proof from above, using forward reasoning throughout
491
521
instead of backward reasoning.
492
522
493
- > silly3' : (n : Nat ) -> (beq_nat n 5 = True -> beq_nat (S (S n)) 7 = True) ->
494
- > True = beq_nat n 5 ->
495
- > True = beq_nat (S (S n)) 7
523
+ > silly3' : (n, m : Nat ) -> (beq_nat n 5 = True -> beq_nat m 7 = True) ->
524
+ > True = beq_nat n 5 -> True = beq_nat m 7
525
+ > silly3' = % runElab silly3_tac
526
+ > where
527
+ > silly3_tac : Elab ()
528
+ > silly3_tac = do
529
+ > [n,m,eq,h] <- intros
530
+ > | _ => fail []
531
+ > hsym <- gensym " hsym"
532
+ > symmetryIn (Var h) hsym
533
+ > happ <- gensym " happ"
534
+ > applyIn (Var eq) (Var hsym) happ
535
+ > happsym <- gensym " happsym"
536
+ > symmetryIn (Var happ) happsym
537
+ > exact $ Var happsym
496
538
497
539
Forward reasoning starts from what is _given_ (premises, previously proven
498
540
theorems) and iteratively draws conclusions from them until the goal is reached.
@@ -659,11 +701,15 @@ The following exercise requires the same pattern.
659
701
660
702
==== Exercise : 2 stars (beq_nat_true)
661
703
704
+ \ todo[inline]{We can't leave this undefined as \ idr{beq_id_true} later depends
705
+ on it. Use \ idr{really_believe_me}? }
706
+
662
707
> beq_nat_true : beq_nat n m = True -> n = m
663
708
> beq_nat_true {n= Z } {m= Z } _ = Refl
664
709
> beq_nat_true {n= (S _ )} {m= Z } Refl impossible
665
710
> beq_nat_true {n= Z } {m= (S _ )} Refl impossible
666
- > beq_nat_true {n= (S n')} {m= (S m')} eq = rewrite beq_nat_true {n= n'} {m= m'} eq in Refl
711
+ > beq_nat_true {n= (S n')} {m= (S m')} eq =
712
+ > rewrite beq_nat_true {n= n'} {m= m'} eq in Refl
667
713
668
714
$\ square$
669
715
@@ -673,7 +719,7 @@ $\square$
673
719
Give a careful informal proof of \ idr{beq_nat_true}, being as explicit as possible
674
720
about quantifiers.
675
721
676
- ( * FILL IN HERE * )
722
+ > -- FILL IN HERE
677
723
678
724
$\ square$
679
725
@@ -870,17 +916,17 @@ Similarly, tentatively unfolding \idr{bar (m+1)} leaves a match whose scrutinee
870
916
is a function application (that, itself, cannot be simplified, even after
871
917
unfolding the definition of \ idr{+ }), so \ idr{Refl } leaves it alone.
872
918
873
- \ todo[inline]{Edit }
874
-
875
- At this point, there are two ways to make progress. One is to use destruct m to
876
- break the proof into two cases, each focusing on a more concrete choice of m (Z
877
- vs S _ ). In each case , the match inside of bar can now make progress, and the
878
- proof is easy to complete.
919
+ At this point, there are two ways to make progress. One is to match on implicit
920
+ parameter \ idr{m} to break the proof into two cases, each focusing on a more
921
+ concrete choice of \ idr{m} (\ idr{Z } vs \ idr{S _ }). In each case , the match
922
+ inside of \ idr{bar} can now make progress, and the proof is easy to complete.
879
923
880
924
> silly_fact_2 : bar m + 1 = bar (m + 1) + 1
881
925
> silly_fact_2 {m= Z } = Refl
882
926
> silly_fact_2 {m= (S _ )} = Refl
883
927
928
+ \ todo[inline]{Edit }
929
+
884
930
This approach works, but it depends on our recognizing that the match hidden
885
931
inside bar is what was preventing us from making progress. A more
886
932
straightforward way to make progress is to explicitly tell Idris to unfold bar.
901
947
902
948
== Using \ idr{destruct} on Compound Expressions
903
949
904
- \ todo[inline]{Edit }
950
+ \ todo[inline]{Edit . Explain \ idr{ with } }
905
951
906
952
We have seen many examples where destruct is used to perform case analysis of
907
953
the value of some variable. But sometimes we need to reason by cases on the
@@ -967,7 +1013,7 @@ like this:
967
1013
> sillyfun1_odd (S (S (S Z ))) Refl | True = Refl
968
1014
> sillyfun1_odd n prf | False with (beq_nat n 5 )
969
1015
> sillyfun1_odd (S (S (S (S (S Z ))))) Refl | False | True = Refl
970
- > sillyfun1_odd n prf | False | False = absurd $ FalseNotTrue prf
1016
+ > sillyfun1_odd n prf | False | False = absurd prf
971
1017
972
1018
\ todo[inline]{Edit the following, since \ idr{with } works fine here as well}
973
1019
0 commit comments