@@ -18,7 +18,8 @@ will see:
18
18
> module Tactics
19
19
20
20
> import Basics
21
- > import Poly
21
+
22
+ import Poly
22
23
23
24
\todo[inline]{Describe \idr{Pruviloj} and \idr{%runElab}}
24
25
@@ -30,6 +31,9 @@ will see:
30
31
31
32
> %language ElabReflection
32
33
34
+ %hide Poly .MumbleGrumble.A
35
+ %hide Poly .MumbleGrumble.B
36
+
33
37
34
38
== The \idr{exact} Tactic
35
39
@@ -114,7 +118,10 @@ Complete the following proof without using `simpl`.
114
118
115
119
> silly_ex : ((n : Nat) -> evenb n = True -> oddb (S n ) = True)
116
120
> -> evenb 3 = True -> oddb 4 = True
117
- > silly_ex = ?silly_ex_rhs
121
+ > silly_ex = ?remove_me -- %runElab silly_ex_tac
122
+ > where
123
+ > silly_ex_tac : Elab ()
124
+ > silly_ex_tac = ?silly_ex_tac_rhs
118
125
119
126
$\square$
120
127
@@ -129,6 +136,7 @@ right sides of the equality are swapped.
129
136
> [_,_,_,_,_] <- apply (Var `{{sym}}) [True, True, True, True, False]
130
137
> | _ => fail [TextPart "Failed while applying", NamePart `{symmetry} ]
131
138
> solve
139
+ > attack
132
140
133
141
> silly3_firsttry : (n : Nat) -> True = beq_nat n 5 ->
134
142
> beq_nat (S (S n )) 7 = True
@@ -144,19 +152,19 @@ tactic, which switches the left and right sides of an equality in the goal.
144
152
145
153
> symmetry
146
154
> exact $ Var h
147
-
155
+ > solve
148
156
149
157
150
158
==== Exercise: 3 stars (apply_exercise1)
151
159
152
160
(_Hint_: You can use \idr{exact} with previously defined lemmas , not just
153
161
hypotheses in the context . Remember that `:search` is your friend.)
154
162
155
- > rev_exercise1 : (l, l' : List Nat ) -> l = rev l' -> l' = rev l
156
- > rev_exercise1 = ?remove_me1 -- %runElab rev_exercise1_tac
157
- > where
158
- > rev_exercise1_tac : Elab ()
159
- > rev_exercise1_tac = ?rev_exercise1_tac_rhs
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
160
168
161
169
$\square$
162
170
@@ -234,114 +242,169 @@ invocation of \idr{apply}.
234
242
$\square$
235
243
236
244
237
- == The inversion Tactic
245
+ == The \idr{ inversion} Tactic
238
246
239
247
Recall the definition of natural numbers :
240
- Inductive Nat : Type :=
241
- | Z : Nat | S : Nat -> Nat.
248
+
249
+ ```idris
250
+ data Nat : Type where
251
+ Z : Nat
252
+ S : Nat -> Nat
253
+ ```
242
254
243
255
It is obvious from this definition that every number has one of two forms :
244
- either it is the constructor Z or it is built by applying the constructor S to
245
- another number . But there is more here than meets the eye: implicit in the
246
- definition (and in our informal understanding of how datatype declarations work
247
- in other programming languages ) are two more facts :
256
+ either it is the constructor \idr{Z} or it is built by applying the constructor
257
+ \idr{S} to another number. But there is more here than meets the eye: implicit
258
+ in the definition (and in our informal understanding of how datatype
259
+ declarations work in other programming languages ) are two more facts :
248
260
249
- - The constructor S is _injective_. That is , if S n = S m , it must be the case
250
- that n = m.
261
+ - The constructor \idr{S} is _injective_ . That is , if \idr{ S n = S m } , it must
262
+ be the case that \idr{ n = m} .
251
263
252
- - The constructors Z and S are _disjoint_. That is , Z is not equal to S n for
253
- any n .
264
+ - The constructors \idr{Z} and \idr{S} are _disjoint_ . That is , \idr{Z} is not
265
+ equal to \idr{ S n } for any \idr{n} .
254
266
255
267
Similar principles apply to all inductively defined types : all constructors are
256
268
injective, and the values built from distinct constructors are never equal . For
257
- lists, the cons constructor is injective and nil is different from every
258
- non-empty list . For booleans , True and False are different. (Since neither True
259
- nor False take any arguments, their injectivity is not interesting.) And so on.
269
+ lists, the \idr{(::)} constructor is injective and \idr{Nil} is different from
270
+ every non -empty list . For booleans , \idr{True} and \idr{False} are different .
271
+ (Since neither \idr{True} nor \idr{False} take any arguments, their injectivity
272
+ is not interesting.) And so on.
260
273
261
- Coq provides a tactic called inversion that allows us to exploit these
262
- principles in proofs. To see how to use it , let's show explicitly that the S
263
- constructor is injective:
274
+ Idris provides a tactic called \idr{injective} that allows us to exploit these
275
+ principles in proofs. To see how to use it , let's show explicitly that the
276
+ \idr{S} constructor is injective:
264
277
265
- Theorem S_injective : ∀(n m : Nat),
266
- S n = S m -> n = m.
267
- Proof.
268
- intros n m H .
278
+ > S_injective : (n, m : Nat) -> S n = S m -> n = m
279
+ > S_injective = %runElab S_injective_tac
280
+ > where
281
+ > covering
282
+ > S_injective_tac : Elab ()
283
+ > S_injective_tac = do
284
+ > [n, m, h] <- intros
285
+ > | _ => fail []
269
286
270
- By writing inversion H at this point, we are asking Coq to generate all
271
- equations that it can infer from H as additional hypotheses , replacing variables
272
- in the goal as it goes . In the present example , this amounts to adding a new
273
- hypothesis H1 : n = m and replacing n by m in the goal.
287
+ By writing \idr{injective (Var h ) res} at this point, we are asking Idris to
288
+ generate all equations that it can infer from \idr{h} as additional hypotheses,
289
+ replacing variables in the goal as it goes . In the present example , this amounts
290
+ to adding a new hypothesis \idr{h1 : n = m} and replacing \idr{n} by \idr{m} in
291
+ the goal .
274
292
275
- inversion H . reflexivity.
276
- Qed.
293
+ \todo[inline]{Explain \idr{gensym}, \idr{unproduct} and \idr{hypothesis}}
294
+
295
+ > res <- gensym "sInj"
296
+ > injective (Var h ) res
297
+ > unproduct (Var res )
298
+ > hypothesis
277
299
278
300
Here's a more interesting example that shows how multiple equations can be
279
301
derived at once.
280
302
281
- Theorem inversion_ex1 : ∀(n m o : Nat),
282
- [n, m] = [o, o] -> [n] = [m].
283
- Proof.
284
- intros n m o H. inversion H . reflexivity. Qed.
285
-
286
- We can name the equations that inversion generates with an as ... clause:
287
-
288
- Theorem inversion_ex2 : ∀(n m : Nat),
289
- [n] = [m] -> n = m.
290
- Proof.
291
- intros n m H . inversion H as [Hnm]. reflexivity. Qed.
303
+ \todo[inline]{Make prettier and contribute to Pruviloj ?}
304
+
305
+ > symmetryIn : Raw -> TTName -> Elab ()
306
+ > symmetryIn t n = do
307
+ > tt <- getTTType t
308
+ > case tt of
309
+ > `((=) {A=~A} {B=~B} ~l ~r) => do
310
+ > af <- forget A
311
+ > bf <- forget B
312
+ > lf <- forget l
313
+ > rf <- forget r
314
+ > let tsym = the Raw $ `(sym {a=~ af} {b=~ bf} {left=~ lf} {right=~ rf} ~ t)
315
+ > tsymty <- forget ! (getTTType tsym)
316
+ > letbind n tsymty tsym
317
+ > _ => 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
+
325
+ \ todo[inline]{Works quite fast in Elab shell but hangs the compiler}
326
+
327
+ > -- inversion_ex1 : (n, m, o : Nat) -> [n, m] = [o, o] -> [n] = [m]
328
+ > -- inversion_ex1 = %runElab inversion_ex1_tac
329
+ > -- where
330
+ > -- inversion_ex1_tac : Elab ()
331
+ > -- inversion_ex1_tac = do
332
+ > -- [n, m, o, eq] <- intros
333
+ > -- | _ => fail []
334
+ > -- eqinj <- gensym "eqinj"
335
+ > -- injective (Var eq) eqinj
336
+ > --
337
+ > -- eqinj2 <- gensym "eqinj2" -- manual destructuring
338
+ > -- both (Var eqinj) !(gensym "natnat") eqinj2
339
+ > -- neqo <- gensym "neqo"
340
+ > -- eqinj3 <- gensym "eqinj3"
341
+ > -- both (Var eqinj2) no eqinj3
342
+ > -- meqos <- gensym "meqos"
343
+ > -- both (Var eqinj3) mos !(gensym "uu")
344
+ > --
345
+ > -- oeqn <- gensym "oeqn"
346
+ > -- symmetryIn (Var neqo) oeqn
347
+ > -- symmetry
348
+ > -- rewriteWith $ Var oeqn
349
+ > -- exact $ Var meqos
350
+ > -- solve
351
+
352
+ Note that we need to pass the parameter \ idr{eqinj} which will be bound to
353
+ equations that \ idr{injective} generates.
292
354
293
355
294
356
==== Exercise : 1 star (inversion_ex3)
295
357
296
- Example inversion_ex3 : ∀(X : Type) (x y z : X)
297
- (l j : list X ),
298
- x :: y :: l = z :: j -> y :: l = x :: j -> x = y.
299
- Proof.
300
-
301
- (* FILL IN HERE *) Admitted.
358
+ > inversion_ex3 : (x, y, z : a) -> (l, j : List a) ->
359
+ > x :: y :: l = z :: j ->
360
+ > y :: l = x :: j ->
361
+ > x = y
362
+ > inversion_ex3 = ? remove_me3 -- %runElab inversion_ex3_tac
363
+ > where
364
+ > inversion_ex3_tac : Elab ()
365
+ > inversion_ex3_tac = ? inversion_ex3_tac_rhs
302
366
303
367
$\ square$
304
368
305
- When used on a hypothesis involving an equality between different
306
- constructors (e.g., S n = Z), inversion solves the goal immediately. Consider
307
- the following proof:
369
+ \ todo[inline]{Edit or remove}
308
370
309
- Theorem beq_nat_0_l : ∀n,
310
- beq_nat 0 n = True -> n = 0.
311
- Proof.
312
- intros n .
371
+ When used on a hypothesis involving an equality between _different_ constructors
372
+ (e. g. , \ idr{S n = Z }), \ idr{injective} solves the goal immediately. Consider the
373
+ following proof :
374
+
375
+ > -- beq_nat_0_l : beq_nat 0 n = True -> n = 0
313
376
314
377
We can proceed by case analysis on n. The first case is trivial.
315
378
316
- destruct n as [| n']. - (* n = 0 *)
317
- intros H . reflexivity.
379
+ > -- beq_nat_0_l {n=Z} prf = %runElab reflexivity
380
+ > -- beq_nat_0_l {n=(S _)} prf = %runElab (do
318
381
319
- However, the second one doesn't look so simple: assuming beq_nat 0 (S n' ) =
320
- True, we must show S n' = 0, but the latter clearly contradictory! The way
321
- forward lies in the assumption. After simplifying the goal state, we see that
322
- beq_nat 0 (S n' ) = True has become False = True:
382
+ However , the second one doesn't look so simple : assuming \idr{ beq_nat 0 (S n') =
383
+ True } , we must show \ idr{ S n' = 0 } , but the latter clearly contradictory! The
384
+ way forward lies in the assumption. After simplifying the goal state, we see
385
+ that \ idr{ beq_nat 0 (S n') = True } has become \ idr{ False = True } :
323
386
324
- - (* n = S n' *)
325
- simpl.
387
+ > -- compute
326
388
327
- If we use inversion on this hypothesis, Coq notices that the subgoal we are
328
- working on is impossible , and therefore removes it from further consideration.
389
+ \ todo[inline]{Finish the script. Use \ idr{disjoint}? }
329
390
330
- intros H . inversion H . Qed.
391
+ If we use inversion on this hypothesis, Idris notices that the subgoal we are
392
+ working on is impossible, and therefore removes it from further consideration.
331
393
332
394
This is an instance of a logical principle known as the principle of explosion,
333
- which asserts that a contradictory hypothesis entails anything , even False
395
+ which asserts that a contradictory hypothesis entails anything, even false
334
396
things!
335
397
336
- Theorem inversion_ex4 : ∀(n : Nat),
337
- S n = Z -> 2 + 2 = 5.
338
- Proof.
339
- intros n contra. inversion contra . Qed.
398
+ \ todo[inline]{How to show impossible cases from Elab ? }
340
399
341
- Theorem inversion_ex5 : ∀(n m : Nat),
342
- False = True -> [n] = [m].
343
- Proof.
344
- intros n m contra . inversion contra . Qed.
400
+ > inversion_ex4 : (n : Nat ) -> S n = Z -> 2 + 2 = 5
401
+ > inversion_ex4 n prf = absurd $ SIsNotZ prf
402
+
403
+ > inversion_ex5 : (n, m : Nat ) -> False = True -> [n] = [m]
404
+ > inversion_ex5 n m prf = absurd $ FalseNotTrue prf
405
+ > where
406
+ > FalseNotTrue : False = True -> Void
407
+ > FalseNotTrue Refl impossible
345
408
346
409
If you find the principle of explosion confusing, remember that these proofs are
347
410
not actually showing that the conclusion of the statement holds. Rather , they
@@ -352,40 +415,42 @@ principle of explosion of more detail in the next chapter.
352
415
353
416
==== Exercise : 1 star (inversion_ex6)
354
417
355
- Example inversion_ex6 : ∀(X : Type)
356
- (x y z : X) (l j : list X ),
357
- x :: y :: l = [] -> y :: l = z :: j -> x = z.
358
- Proof.
359
-
360
- (* FILL IN HERE *) Admitted.
418
+ > inversion_ex6 : (x, y, z : a) -> (l, j : List a) ->
419
+ > x :: y :: l = [] ->
420
+ > y :: l = z :: j ->
421
+ > x = z
422
+ > inversion_ex6 x y z l j prf prf1 = ? inversion_ex6_rhs
361
423
362
424
$\ square$
363
425
364
- To summarize this discussion , suppose H is a hypothesis in the context
426
+ To summarize this discussion, suppose \ idr{h} is a hypothesis in the context
365
427
or a previously proven lemma of the form
366
428
367
- c a1 a2 ... an = d b1 b2 ... bm
429
+ \ idr{c a1 a2 ... an = d b1 b2 ... bm}
430
+
431
+ \ todo[inline]{Edit , especially the \ idr{disjoint} part}
368
432
369
- for some constructors c and d and arguments a1 ... an and b1 ... bm. Then
370
- inversion H has the following effect :
433
+ for some constructors \ idr{c} and \ idr{d} and arguments \ idr{a1 ... an} and
434
+ \ idr{b1 ... bm}. Then \ idr{injective h} and \ idr{disjoint h} have the following
435
+ effects :
371
436
372
- - If c and d are the same constructor , then, by the injectivity of this
373
- constructor, we know that a1 = b1, a2 = b2, etc. The inversion H adds these
374
- facts to the context and tries to use them to rewrite the goal.
437
+ - If \ idr{c} and \ idr{d} are the same constructor, then , by the injectivity of
438
+ this constructor, we know that \ idr{a1 = b1}, \ idr{a2 = b2}, etc. The
439
+ \ idr{injective h} adds these facts to the context and tries to use them to
440
+ rewrite the goal.
375
441
376
- - If c and d are different constructors, then the hypothesis H is
377
- contradictory, and the current goal doesn't have to be considered at all. In
378
- this case , inversion H marks the current goal as completed and pops it off
379
- the goal stack.
442
+ - If \ idr{c} and \ idr{d} are different constructors, then the hypothesis
443
+ \ idr{h} is contradictory, and the current goal doesn't have to be considered
444
+ at all . In this case , \ idr{disjoint h} marks the current goal as completed
445
+ and pops it off the goal stack.
380
446
381
- The injectivity of constructors allows us to reason that ∀ ( n m : Nat), S n = S
382
- m -> n = m. The converse of this implication is an instance of a more general
383
- fact about both constructors and functions , which we will find useful in a few
384
- places below :
447
+ The injectivity of constructors allows us to reason that \ idr{(n, m : Nat ) -> S
448
+ n = S m -> n = m} . The converse of this implication is an instance of a more
449
+ general fact about both constructors and functions, which we will find useful in
450
+ a few places below :
385
451
386
- Theorem f_equal : ∀(A B : Type) (f: A -> B) (x y : A),
387
- x = y -> f x = f y .
388
- Proof. intros A B f x y eq. rewrite eq . reflexivity. Qed.
452
+ > 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
389
454
390
455
391
456
== Using Tactics on Hypotheses
0 commit comments