Mercurial > cpdt > repo
comparison src/Match.v @ 330:49c6aa7d2148
Another Match exercise
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Tue, 27 Sep 2011 18:20:23 -0400 |
parents | d7178fb77321 |
children | 2eeb96aa0426 |
comparison
equal
deleted
inserted
replaced
329:d7178fb77321 | 330:49c6aa7d2148 |
---|---|
1094 | 1094 |
1095 [| [ |- ex ( A := ?T) _ ] => ...] | 1095 [| [ |- ex ( A := ?T) _ ] => ...] |
1096 | 1096 |
1097 The [equate] tactic used as an example in this chapter will probably be useful, to unify two terms, for instance if the first is a unification variable whose value you want to set. | 1097 The [equate] tactic used as an example in this chapter will probably be useful, to unify two terms, for instance if the first is a unification variable whose value you want to set. |
1098 [[ | 1098 [[ |
1099 Ltac equate E1 E2 := let H := fresh in | 1099 Ltac equate E1 E2 := let H := fresh in |
1100 assert (H : E1 = E2) by reflexivity; clear H. | 1100 assert (H : E1 = E2) by reflexivity; clear H. |
1101 ]] | 1101 ]] |
1102 | 1102 |
1103 Finally, there are some minor complications surrounding overloading of the [*] operator for both numeric multiplication and Cartesian product for sets (i.e., pair types). To ensure that an Ltac pattern is using the type version, write it like this: | 1103 Finally, there are some minor complications surrounding overloading of the [*] operator for both numeric multiplication and Cartesian product for sets (i.e., pair types). To ensure that an Ltac pattern is using the type version, write it like this: |
1104 | 1104 |
1105 [| (?T1 * ?T2)%type => ...] | 1105 [| (?T1 * ?T2)%type => ...]#</li># |
1106 | |
1107 %\item%#<li># An exercise in the last chapter dealt with automating proofs about rings using [eauto], where we must prove some odd-looking theorems to push proof search in a direction where unification does all the work. Algebraic proofs consist mostly of rewriting in equations, so we might hope that the [autorewrite] tactic would yield more natural automated proofs. Indeed, consider this example within the same formulation of ring theory that we dealt with last chapter, where each of the three axioms has been added to the rewrite hint database [cpdt] using [Hint Rewrite]: | |
1108 [[ | |
1109 Theorem test1 : forall a b, a * b * i b = a. | |
1110 intros; autorewrite with cpdt; reflexivity. | |
1111 Qed. | |
1112 ]] | |
1113 | |
1114 So far so good. However, consider this further example: | |
1115 [[ | |
1116 Theorem test2 : forall a, a * e * i a * i e = e. | |
1117 intros; autorewrite with cpdt. | |
1118 ]] | |
1119 | |
1120 The goal is merely reduced to [a * (i a * i e) = e], which of course [reflexivity] cannot prove. The essential problem is that [autorewrite] does not do backtracking search. Instead, it follows a %``%#"#greedy#"#%''% approach, at each stage choosing a rewrite to perform and then never allowing that rewrite to be undone. An early mistake can doom the whole process. | |
1121 | |
1122 The task in this problem is to use Ltac to implement a backtracking version of [autorewrite] that works much like [eauto], in that its inputs are a database of hint lemmas and a bound on search depth. Here our search trees will have uses of [rewrite] at their nodes, rather than uses of [eapply] as in the case of [eauto], and proofs must be finished by [reflexivity]. | |
1123 | |
1124 An invocation to the tactic to prove [test2] might look like this: | |
1125 [[ | |
1126 rewriter (right_identity, (right_inverse, tt)) 3. | |
1127 ]] | |
1128 | |
1129 The first argument gives the set of lemmas to consider, as a kind of list encoded with pair types. Such a format cannot be analyzed directly by Gallina programs, but Ltac allows us much more freedom to deconstruct syntax. For example, to case analyze such a list found in a variable [x], we need only write: | |
1130 [[ | |
1131 match x with | |
1132 | (?lemma, ?more) => ... | |
1133 end | |
1134 ]] | |
1135 | |
1136 In the body of the case analysis, [lemma] will be bound to the first lemma, and [more] will be bound to the remaining lemmas. There is no need to consider a case for [tt], our stand-in for [nil]. This is because lack of any matching pattern will trigger failure, which is exactly the outcome we would like upon reaching the end of the lemma list without finding one that applies. The tactic will fail, triggering backtracking to some previous [match]. | |
1137 | |
1138 There are different kinds of backtracking, corresponding to different sorts of decisions to be made. The examples considered above can be handled with backtracking that only reconsiders decisions about the order in which to apply rewriting lemmas. A full-credit solution need only handle that kind of backtracking, considering all rewriting sequences up to the length bound passed to your tactic. A good test of this level of applicability is to prove both [test1] and [test2] above. However, some theorems could only be proved using a smarter tactic that considers not only order of rewriting lemma uses, but also choice of arguments to the lemmas. That is, at some points in a proof, the same lemma may apply at multiple places within the goal formula, and some choices may lead to stuck proof states while others lead to success. For an extra challenge (without any impact on the grade for the problem), you might try beefing up your tactic to do backtracking on argument choice, too.#</li># | |
1106 | 1139 |
1107 #</ol>#%\end{enumerate}% *) | 1140 #</ol>#%\end{enumerate}% *) |