Mercurial > cpdt > repo
comparison src/Large.v @ 238:0a2146dafa8e
Start of maint & debug
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Mon, 07 Dec 2009 16:15:08 -0500 |
parents | 91eed1e3e3a4 |
children | a3f0cdcb09c3 |
comparison
equal
deleted
inserted
replaced
237:91eed1e3e3a4 | 238:0a2146dafa8e |
---|---|
200 | 200 |
201 (** Now we are in a position to see how much nicer is the style of proof that we have followed in most of this book. *) | 201 (** Now we are in a position to see how much nicer is the style of proof that we have followed in most of this book. *) |
202 | 202 |
203 Reset eval_times. | 203 Reset eval_times. |
204 | 204 |
205 Theorem eval_times : forall k e, | 205 Hint Rewrite mult_plus_distr_l : cpdt. |
206 eval (times k e) = k * eval e. | 206 |
207 Hint Rewrite mult_plus_distr_l mult_assoc : cpdt. | 207 Theorem eval_times : forall k e, |
208 | 208 eval (times k e) = k * eval e. |
209 induction e; crush. | 209 induction e; crush. |
210 Qed. | 210 Qed. |
211 | 211 |
212 (** This style is motivated by a hard truth: one person's manual proof script is almost always mostly inscrutable to most everyone else. I claim that step-by-step formal proofs are a poor way of conveying information. Thus, we had might as well cut out the steps and automate as much as possible. | 212 (** This style is motivated by a hard truth: one person's manual proof script is almost always mostly inscrutable to most everyone else. I claim that step-by-step formal proofs are a poor way of conveying information. Thus, we had might as well cut out the steps and automate as much as possible. |
213 | 213 |
274 (** In the limit, a complicated inductive proof might rely on one hint for each inductive case. The lemma for each hint could restate the associated case. Compared to manual proof scripts, we arrive at more readable results. Scripts no longer need to depend on the order in which cases are generated. The lemmas are easier to digest separately than are fragments of tactic code, since lemma statements include complete proof contexts. Such contexts can only be extracted from monolithic manual proofs by stepping through scripts interactively. | 274 (** In the limit, a complicated inductive proof might rely on one hint for each inductive case. The lemma for each hint could restate the associated case. Compared to manual proof scripts, we arrive at more readable results. Scripts no longer need to depend on the order in which cases are generated. The lemmas are easier to digest separately than are fragments of tactic code, since lemma statements include complete proof contexts. Such contexts can only be extracted from monolithic manual proofs by stepping through scripts interactively. |
275 | 275 |
276 The more common situation is that a large induction has several easy cases that automation makes short work of. In the remaining cases, automation performs some standard simplification. Among these cases, some may require quite involved proofs; such a case may deserve a hint lemma of its own, where the lemma statement may copy the simplified version of the case. Alternatively, the proof script for the main theorem may be extended with some automation code targeted at the specific case. Even such targeted scripting is more desirable than manual proving, because it may be read and understood without knowledge of a proof's hierarchical structure, case ordering, or name binding structure. *) | 276 The more common situation is that a large induction has several easy cases that automation makes short work of. In the remaining cases, automation performs some standard simplification. Among these cases, some may require quite involved proofs; such a case may deserve a hint lemma of its own, where the lemma statement may copy the simplified version of the case. Alternatively, the proof script for the main theorem may be extended with some automation code targeted at the specific case. Even such targeted scripting is more desirable than manual proving, because it may be read and understood without knowledge of a proof's hierarchical structure, case ordering, or name binding structure. *) |
277 | 277 |
278 | 278 |
279 (** * Debugging and Maintaining Automation *) | |
280 | |
281 (** Fully-automated proofs are desirable because they open up possibilities for automatic adaptation to changes of specification. A well-engineered script within a narrow domain can survive many changes to the formulation of the problem it solves. Still, as we are working with higher-order logic, most theorems fall within no obvious decidable theories. It is inevitable that most long-lived automated proofs will need updating. | |
282 | |
283 Before we are ready to update our proofs, we need to write them in the first place. While fully-automated scripts are most robust to changes of specification, it is hard to write every new proof directly in that form. Instead, it is useful to begin a theorem with exploratory proving and then gradually refine it into a suitable automated form. | |
284 | |
285 Consider this theorem from Chapter 7, which we begin by proving in a mostly manual way, invoking [crush] after each steop to discharge any low-hanging fruit. Our manual effort involves choosing which expressions to case-analyze on. *) | |
286 | |
287 (* begin hide *) | |
288 Require Import MoreDep. | |
289 (* end hide *) | |
290 | |
291 Theorem cfold_correct : forall t (e : exp t), expDenote e = expDenote (cfold e). | |
292 induction e; crush. | |
293 | |
294 dep_destruct (cfold e1); crush. | |
295 dep_destruct (cfold e2); crush. | |
296 | |
297 dep_destruct (cfold e1); crush. | |
298 dep_destruct (cfold e2); crush. | |
299 | |
300 dep_destruct (cfold e1); crush. | |
301 dep_destruct (cfold e2); crush. | |
302 | |
303 dep_destruct (cfold e1); crush. | |
304 dep_destruct (expDenote e1); crush. | |
305 | |
306 dep_destruct (cfold e); crush. | |
307 | |
308 dep_destruct (cfold e); crush. | |
309 Qed. | |
310 | |
311 (** In this complete proof, it is hard to avoid noticing a pattern. We rework the proof, abstracting over the patterns we find. *) | |
312 | |
313 Reset cfold_correct. | |
314 | |
315 Theorem cfold_correct : forall t (e : exp t), expDenote e = expDenote (cfold e). | |
316 induction e; crush. | |
317 | |
318 (** The expression we want to destruct here turns out to be the discriminee of a [match], and we can easily enough write a tactic that destructs all such expressions. *) | |
319 | |
320 Ltac t := | |
321 repeat (match goal with | |
322 | [ |- context[match ?E with NConst _ => _ | Plus _ _ => _ | |
323 | Eq _ _ => _ | BConst _ => _ | And _ _ => _ | |
324 | If _ _ _ _ => _ | Pair _ _ _ _ => _ | |
325 | Fst _ _ _ => _ | Snd _ _ _ => _ end] ] => | |
326 dep_destruct E | |
327 end; crush). | |
328 | |
329 t. | |
330 | |
331 (** This tactic invocation discharges the whole case. It does the same on the next two cases, but it gets stuck on the fourth case. *) | |
332 | |
333 t. | |
334 | |
335 t. | |
336 | |
337 t. | |
338 | |
339 (** The subgoal's conclusion is: | |
340 [[ | |
341 ============================ | |
342 (if expDenote e1 then expDenote (cfold e2) else expDenote (cfold e3)) = | |
343 expDenote (if expDenote e1 then cfold e2 else cfold e3) | |
344 | |
345 ]] | |
346 | |
347 We need to expand our [t] tactic to handle this case. *) | |
348 | |
349 Ltac t' := | |
350 repeat (match goal with | |
351 | [ |- context[match ?E with NConst _ => _ | Plus _ _ => _ | |
352 | Eq _ _ => _ | BConst _ => _ | And _ _ => _ | |
353 | If _ _ _ _ => _ | Pair _ _ _ _ => _ | |
354 | Fst _ _ _ => _ | Snd _ _ _ => _ end] ] => | |
355 dep_destruct E | |
356 | [ |- (if ?E then _ else _) = _ ] => destruct E | |
357 end; crush). | |
358 | |
359 t'. | |
360 | |
361 (** Now the goal is discharged, but [t'] has no effect on the next subgoal. *) | |
362 | |
363 t'. | |
364 | |
365 (** A final revision of [t] finishes the proof. *) | |
366 | |
367 Ltac t'' := | |
368 repeat (match goal with | |
369 | [ |- context[match ?E with NConst _ => _ | Plus _ _ => _ | |
370 | Eq _ _ => _ | BConst _ => _ | And _ _ => _ | |
371 | If _ _ _ _ => _ | Pair _ _ _ _ => _ | |
372 | Fst _ _ _ => _ | Snd _ _ _ => _ end] ] => | |
373 dep_destruct E | |
374 | [ |- (if ?E then _ else _) = _ ] => destruct E | |
375 | [ |- context[match pairOut ?E with Some _ => _ | |
376 | None => _ end] ] => | |
377 dep_destruct E | |
378 end; crush). | |
379 | |
380 t''. | |
381 | |
382 t''. | |
383 Qed. | |
384 | |
385 (** We can take the final tactic and move it into the initial part of the proof script, arriving at a nicely-automated proof. *) | |
386 | |
387 Reset t. | |
388 | |
389 Theorem cfold_correct : forall t (e : exp t), expDenote e = expDenote (cfold e). | |
390 induction e; crush; | |
391 repeat (match goal with | |
392 | [ |- context[match ?E with NConst _ => _ | Plus _ _ => _ | |
393 | Eq _ _ => _ | BConst _ => _ | And _ _ => _ | |
394 | If _ _ _ _ => _ | Pair _ _ _ _ => _ | |
395 | Fst _ _ _ => _ | Snd _ _ _ => _ end] ] => | |
396 dep_destruct E | |
397 | [ |- (if ?E then _ else _) = _ ] => destruct E | |
398 | [ |- context[match pairOut ?E with Some _ => _ | |
399 | None => _ end] ] => | |
400 dep_destruct E | |
401 end; crush). | |
402 Qed. | |
403 | |
404 | |
279 (** * Modules *) | 405 (** * Modules *) |
280 | 406 |
281 Module Type GROUP. | 407 Module Type GROUP. |
282 Parameter G : Set. | 408 Parameter G : Set. |
283 Parameter f : G -> G -> G. | 409 Parameter f : G -> G -> G. |