Mercurial > cpdt > repo
comparison src/Match.v @ 141:ce4cc7fa9b2b
Templatize Match
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Mon, 27 Oct 2008 10:31:57 -0400 |
parents | 8cce3247496b |
children | cbf2f74a5130 |
comparison
equal
deleted
inserted
replaced
140:8cce3247496b | 141:ce4cc7fa9b2b |
---|---|
38 The basic hints for [auto] and [eauto] are [Hint Immediate lemma], asking to try solving a goal immediately by applying the premise-free lemma; [Resolve lemma], which does the same but may add new premises that are themselves to be subjects of proof search; [Constructor type], which acts like [Resolve] applied to every constructor of an inductive type; and [Unfold ident], which tries unfolding [ident] when it appears at the head of a proof goal. Each of these [Hint] commands may be used with a suffix, as in [Hint Resolve lemma : my_db]. This adds the hint only to the specified database, so that it would only be used by, for instance, [auto with my_db]. An additional argument to [auto] specifies the maximum depth of proof trees to search in depth-first order, as in [auto 8] or [auto 8 with my_db]. The default depth is 5. | 38 The basic hints for [auto] and [eauto] are [Hint Immediate lemma], asking to try solving a goal immediately by applying the premise-free lemma; [Resolve lemma], which does the same but may add new premises that are themselves to be subjects of proof search; [Constructor type], which acts like [Resolve] applied to every constructor of an inductive type; and [Unfold ident], which tries unfolding [ident] when it appears at the head of a proof goal. Each of these [Hint] commands may be used with a suffix, as in [Hint Resolve lemma : my_db]. This adds the hint only to the specified database, so that it would only be used by, for instance, [auto with my_db]. An additional argument to [auto] specifies the maximum depth of proof trees to search in depth-first order, as in [auto 8] or [auto 8 with my_db]. The default depth is 5. |
39 | 39 |
40 All of these [Hint] commands can be issued alternatively with a more primitive hint kind, [Extern]. A few examples should do best to explain how [Hint Extern] works. *) | 40 All of these [Hint] commands can be issued alternatively with a more primitive hint kind, [Extern]. A few examples should do best to explain how [Hint Extern] works. *) |
41 | 41 |
42 Theorem bool_neq : true <> false. | 42 Theorem bool_neq : true <> false. |
43 (* begin thide *) | |
43 auto. | 44 auto. |
44 (** [crush] would have discharged this goal, but the default hint database for [auto] contains no hint that applies. *) | 45 (** [crush] would have discharged this goal, but the default hint database for [auto] contains no hint that applies. *) |
45 Abort. | 46 Abort. |
46 | 47 |
47 (** It is hard to come up with a [bool]-specific hint that is not just a restatement of the theorem we mean to prove. Luckily, a simpler form suffices. *) | 48 (** It is hard to come up with a [bool]-specific hint that is not just a restatement of the theorem we mean to prove. Luckily, a simpler form suffices. *) |
49 Hint Extern 1 (_ <> _) => congruence. | 50 Hint Extern 1 (_ <> _) => congruence. |
50 | 51 |
51 Theorem bool_neq : true <> false. | 52 Theorem bool_neq : true <> false. |
52 auto. | 53 auto. |
53 Qed. | 54 Qed. |
55 (* end thide *) | |
54 | 56 |
55 (** Our hint says: "whenever the conclusion matches the pattern [_ <> _], try applying [congruence]." The [1] is a cost for this rule. During proof search, whenever multiple rules apply, rules are tried in increasing cost order, so it pays to assign high costs to relatively expensive [Extern] hints. | 57 (** Our hint says: "whenever the conclusion matches the pattern [_ <> _], try applying [congruence]." The [1] is a cost for this rule. During proof search, whenever multiple rules apply, rules are tried in increasing cost order, so it pays to assign high costs to relatively expensive [Extern] hints. |
56 | 58 |
57 [Extern] hints may be implemented with the full Ltac language. This example shows a case where a hint uses a [match]. *) | 59 [Extern] hints may be implemented with the full Ltac language. This example shows a case where a hint uses a [match]. *) |
58 | 60 |
61 Variables P Q : A -> Prop. | 63 Variables P Q : A -> Prop. |
62 | 64 |
63 Hypothesis both : forall x, P x /\ Q x. | 65 Hypothesis both : forall x, P x /\ Q x. |
64 | 66 |
65 Theorem forall_and : forall z, P z. | 67 Theorem forall_and : forall z, P z. |
68 (* begin thide *) | |
66 crush. | 69 crush. |
67 (** [crush] makes no progress beyond what [intros] would have accomplished. [auto] will not apply the hypothesis [both] to prove the goal, because the conclusion of [both] does not unify with the conclusion of the goal. However, we can teach [auto] to handle this kind of goal. *) | 70 (** [crush] makes no progress beyond what [intros] would have accomplished. [auto] will not apply the hypothesis [both] to prove the goal, because the conclusion of [both] does not unify with the conclusion of the goal. However, we can teach [auto] to handle this kind of goal. *) |
68 | 71 |
69 Hint Extern 1 (P ?X) => | 72 Hint Extern 1 (P ?X) => |
70 match goal with | 73 match goal with |
71 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X)) | 74 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X)) |
72 end. | 75 end. |
73 | 76 |
74 auto. | 77 auto. |
75 Qed. | 78 Qed. |
79 (* end thide *) | |
76 | 80 |
77 (** We see that an [Extern] pattern may bind unification variables that we use in the associated tactic. [proj1] is a function from the standard library for extracting a proof of [R] from a proof of [R /\ S]. *) | 81 (** We see that an [Extern] pattern may bind unification variables that we use in the associated tactic. [proj1] is a function from the standard library for extracting a proof of [R] from a proof of [R /\ S]. *) |
78 End forall_and. | 82 End forall_and. |
79 | 83 |
80 (** After our success on this example, we might get more ambitious and seek to generalize the hint to all possible predicates [P]. | 84 (** After our success on this example, we might get more ambitious and seek to generalize the hint to all possible predicates [P]. |
161 | 165 |
162 Section garden_path. | 166 Section garden_path. |
163 Variable P : A -> Prop. | 167 Variable P : A -> Prop. |
164 Variable g : A -> A. | 168 Variable g : A -> A. |
165 Hypothesis f_g : forall x, P x -> f x = g x. | 169 Hypothesis f_g : forall x, P x -> f x = g x. |
170 (* begin thide *) | |
166 Hint Rewrite f_g using assumption : my_db. | 171 Hint Rewrite f_g using assumption : my_db. |
172 (* end thide *) | |
167 | 173 |
168 Lemma f_f_f' : forall x, f (f (f x)) = f x. | 174 Lemma f_f_f' : forall x, f (f (f x)) = f x. |
175 (* begin thide *) | |
169 intros; autorewrite with my_db; reflexivity. | 176 intros; autorewrite with my_db; reflexivity. |
170 Qed. | 177 Qed. |
178 (* end thide *) | |
171 | 179 |
172 (** [autorewrite] will still use [f_g] when the generated premise is among our assumptions. *) | 180 (** [autorewrite] will still use [f_g] when the generated premise is among our assumptions. *) |
173 | 181 |
174 Lemma f_f_f_g : forall x, P x -> f (f x) = g x. | 182 Lemma f_f_f_g : forall x, P x -> f (f x) = g x. |
183 (* begin thide *) | |
175 intros; autorewrite with my_db; reflexivity. | 184 intros; autorewrite with my_db; reflexivity. |
185 (* end thide *) | |
176 Qed. | 186 Qed. |
177 End garden_path. | 187 End garden_path. |
178 | 188 |
179 (** It can also be useful to use the [autorewrite with db in *] form, which does rewriting in hypotheses, as well as in the conclusion. *) | 189 (** It can also be useful to use the [autorewrite with db in *] form, which does rewriting in hypotheses, as well as in the conclusion. *) |
180 | 190 |
181 Lemma in_star : forall x y, f (f (f (f x))) = f (f y) | 191 Lemma in_star : forall x y, f (f (f (f x))) = f (f y) |
182 -> f x = f (f (f y)). | 192 -> f x = f (f (f y)). |
193 (* begin thide *) | |
183 intros; autorewrite with my_db in *; assumption. | 194 intros; autorewrite with my_db in *; assumption. |
195 (* end thide *) | |
184 Qed. | 196 Qed. |
185 | 197 |
186 End autorewrite. | 198 End autorewrite. |
187 | 199 |
188 | 200 |
190 | 202 |
191 (** We have already seen many examples of Ltac programs. In the rest of this chapter, we attempt to give a more principled introduction to the important features and design patterns. | 203 (** We have already seen many examples of Ltac programs. In the rest of this chapter, we attempt to give a more principled introduction to the important features and design patterns. |
192 | 204 |
193 One common use for [match] tactics is identification of subjects for case analysis, as we see in this tactic definition. *) | 205 One common use for [match] tactics is identification of subjects for case analysis, as we see in this tactic definition. *) |
194 | 206 |
207 (* begin thide *) | |
195 Ltac find_if := | 208 Ltac find_if := |
196 match goal with | 209 match goal with |
197 | [ |- if ?X then _ else _ ] => destruct X | 210 | [ |- if ?X then _ else _ ] => destruct X |
198 end. | 211 end. |
212 (* end thide *) | |
199 | 213 |
200 (** The tactic checks if the conclusion is an [if], [destruct]ing the test expression if so. Certain classes of theorem are trivial to prove automatically with such a tactic. *) | 214 (** The tactic checks if the conclusion is an [if], [destruct]ing the test expression if so. Certain classes of theorem are trivial to prove automatically with such a tactic. *) |
201 | 215 |
202 Theorem hmm : forall (a b c : bool), | 216 Theorem hmm : forall (a b c : bool), |
203 if a | 217 if a |
205 then True | 219 then True |
206 else True | 220 else True |
207 else if c | 221 else if c |
208 then True | 222 then True |
209 else True. | 223 else True. |
224 (* begin thide *) | |
210 intros; repeat find_if; constructor. | 225 intros; repeat find_if; constructor. |
211 Qed. | 226 Qed. |
227 (* end thide *) | |
212 | 228 |
213 (** The [repeat] that we use here is called a %\textit{%#<i>#tactical#</i>#%}%, or tactic combinator. The behavior of [repeat t] is to loop through running [t], running [t] on all generated subgoals, running [t] on %\textit{%#<i>#their#</i>#%}% generated subgoals, and so on. When [t] fails at any point in this search tree, that particular subgoal is left to be handled by later tactics. Thus, it is important never to use [repeat] with a tactic that always succeeds. | 229 (** The [repeat] that we use here is called a %\textit{%#<i>#tactical#</i>#%}%, or tactic combinator. The behavior of [repeat t] is to loop through running [t], running [t] on all generated subgoals, running [t] on %\textit{%#<i>#their#</i>#%}% generated subgoals, and so on. When [t] fails at any point in this search tree, that particular subgoal is left to be handled by later tactics. Thus, it is important never to use [repeat] with a tactic that always succeeds. |
214 | 230 |
215 Another very useful Ltac building block is %\textit{%#<i>#context patterns#</i>#%}%. *) | 231 Another very useful Ltac building block is %\textit{%#<i>#context patterns#</i>#%}%. *) |
216 | 232 |
233 (* begin thide *) | |
217 Ltac find_if_inside := | 234 Ltac find_if_inside := |
218 match goal with | 235 match goal with |
219 | [ |- context[if ?X then _ else _] ] => destruct X | 236 | [ |- context[if ?X then _ else _] ] => destruct X |
220 end. | 237 end. |
238 (* end thide *) | |
221 | 239 |
222 (** The behavior of this tactic is to find any subterm of the conclusion that is an [if] and then [destruct] the test expression. This version subsumes [find_if]. *) | 240 (** The behavior of this tactic is to find any subterm of the conclusion that is an [if] and then [destruct] the test expression. This version subsumes [find_if]. *) |
223 | 241 |
224 Theorem hmm' : forall (a b c : bool), | 242 Theorem hmm' : forall (a b c : bool), |
225 if a | 243 if a |
227 then True | 245 then True |
228 else True | 246 else True |
229 else if c | 247 else if c |
230 then True | 248 then True |
231 else True. | 249 else True. |
250 (* begin thide *) | |
232 intros; repeat find_if_inside; constructor. | 251 intros; repeat find_if_inside; constructor. |
233 Qed. | 252 Qed. |
253 (* end thide *) | |
234 | 254 |
235 (** We can also use [find_if_inside] to prove goals that [find_if] does not simplify sufficiently. *) | 255 (** We can also use [find_if_inside] to prove goals that [find_if] does not simplify sufficiently. *) |
236 | 256 |
237 Theorem duh2 : forall (a b : bool), | 257 Theorem hmm2 : forall (a b : bool), |
238 (if a then 42 else 42) = (if b then 42 else 42). | 258 (if a then 42 else 42) = (if b then 42 else 42). |
259 (* begin thide *) | |
239 intros; repeat find_if_inside; reflexivity. | 260 intros; repeat find_if_inside; reflexivity. |
240 Qed. | 261 Qed. |
262 (* end thide *) | |
241 | 263 |
242 (** Many decision procedures can be coded in Ltac via "[repeat match] loops." For instance, we can implement a subset of the functionality of [tauto]. *) | 264 (** Many decision procedures can be coded in Ltac via "[repeat match] loops." For instance, we can implement a subset of the functionality of [tauto]. *) |
243 | 265 |
266 (* begin thide *) | |
244 Ltac my_tauto := | 267 Ltac my_tauto := |
245 repeat match goal with | 268 repeat match goal with |
246 | [ H : ?P |- ?P ] => exact H | 269 | [ H : ?P |- ?P ] => exact H |
247 | 270 |
248 | [ |- True ] => constructor | 271 | [ |- True ] => constructor |
255 | 278 |
256 | [ H1 : ?P -> ?Q, H2 : ?P |- _ ] => | 279 | [ H1 : ?P -> ?Q, H2 : ?P |- _ ] => |
257 let H := fresh "H" in | 280 let H := fresh "H" in |
258 generalize (H1 H2); clear H1; intro H | 281 generalize (H1 H2); clear H1; intro H |
259 end. | 282 end. |
283 (* end thide *) | |
260 | 284 |
261 (** Since [match] patterns can share unification variables between hypothesis and conclusion patterns, it is easy to figure out when the conclusion matches a hypothesis. The [exact] tactic solves a goal completely when given a proof term of the proper type. | 285 (** Since [match] patterns can share unification variables between hypothesis and conclusion patterns, it is easy to figure out when the conclusion matches a hypothesis. The [exact] tactic solves a goal completely when given a proof term of the proper type. |
262 | 286 |
263 It is also trivial to implement the "introduction rules" for a few of the connectives. Implementing elimination rules is only a little more work, since we must bind a name for a hypothesis to [destruct]. | 287 It is also trivial to implement the "introduction rules" for a few of the connectives. Implementing elimination rules is only a little more work, since we must bind a name for a hypothesis to [destruct]. |
264 | 288 |
266 | 290 |
267 Section propositional. | 291 Section propositional. |
268 Variables P Q R : Prop. | 292 Variables P Q R : Prop. |
269 | 293 |
270 Theorem propositional : (P \/ Q \/ False) /\ (P -> Q) -> True /\ Q. | 294 Theorem propositional : (P \/ Q \/ False) /\ (P -> Q) -> True /\ Q. |
295 (* begin thide *) | |
271 my_tauto. | 296 my_tauto. |
272 Qed. | 297 Qed. |
298 (* end thide *) | |
273 End propositional. | 299 End propositional. |
274 | 300 |
275 (** It was relatively easy to implement modus ponens, because we do not lose information by clearing every implication that we use. If we want to implement a similarly-complete procedure for quantifier instantiation, we need a way to ensure that a particular proposition is not already included among our hypotheses. To do that effectively, we first need to learn a bit more about the semantics of [match]. | 301 (** It was relatively easy to implement modus ponens, because we do not lose information by clearing every implication that we use. If we want to implement a similarly-complete procedure for quantifier instantiation, we need a way to ensure that a particular proposition is not already included among our hypotheses. To do that effectively, we first need to learn a bit more about the semantics of [match]. |
276 | 302 |
277 It is tempting to assume that [match] works like it does in ML. In fact, there are a few critical differences in its behavior. One is that we may include arbitrary expressions in patterns, instead of being restricted to variables and constructors. Another is that the same variable may appear multiple times, inducing an implicit equality constraint. | 303 It is tempting to assume that [match] works like it does in ML. In fact, there are a few critical differences in its behavior. One is that we may include arbitrary expressions in patterns, instead of being restricted to variables and constructors. Another is that the same variable may appear multiple times, inducing an implicit equality constraint. |
283 Theorem m1 : True. | 309 Theorem m1 : True. |
284 match goal with | 310 match goal with |
285 | [ |- _ ] => intro | 311 | [ |- _ ] => intro |
286 | [ |- True ] => constructor | 312 | [ |- True ] => constructor |
287 end. | 313 end. |
288 Qed. | 314 (* begin thide *) |
315 Qed. | |
316 (* end thide *) | |
289 | 317 |
290 (** The first case matches trivially, but its body tactic fails, since the conclusion does not begin with a quantifier or implication. In a similar ML match, that would mean that the whole pattern-match fails. In Coq, we backtrack and try the next pattern, which also matches. Its body tactic succeeds, so the overall tactic succeeds as well. | 318 (** The first case matches trivially, but its body tactic fails, since the conclusion does not begin with a quantifier or implication. In a similar ML match, that would mean that the whole pattern-match fails. In Coq, we backtrack and try the next pattern, which also matches. Its body tactic succeeds, so the overall tactic succeeds as well. |
291 | 319 |
292 The example shows how failure can move to a different pattern within a [match]. Failure can also trigger an attempt to find %\textit{%#<i>#a different way of matching a single pattern#</i>#%}%. Consider another example: *) | 320 The example shows how failure can move to a different pattern within a [match]. Failure can also trigger an attempt to find %\textit{%#<i>#a different way of matching a single pattern#</i>#%}%. Consider another example: *) |
293 | 321 |
302 Q | 330 Q |
303 ]] | 331 ]] |
304 | 332 |
305 By applying [pose], a convenient debugging tool for "leaking information out of [match]es," we see that this [match] first tries binding [H] to [H1], which cannot be used to prove [Q]. Nonetheless, the following variation on the tactic succeeds at proving the goal: *) | 333 By applying [pose], a convenient debugging tool for "leaking information out of [match]es," we see that this [match] first tries binding [H] to [H1], which cannot be used to prove [Q]. Nonetheless, the following variation on the tactic succeeds at proving the goal: *) |
306 | 334 |
335 (* begin thide *) | |
307 match goal with | 336 match goal with |
308 | [ H : _ |- _ ] => exact H | 337 | [ H : _ |- _ ] => exact H |
309 end. | 338 end. |
310 Qed. | 339 Qed. |
340 (* end thide *) | |
311 | 341 |
312 (** The tactic first unifies [H] with [H1], as before, but [exact H] fails in that case, so the tactic engine searches for more possible values of [H]. Eventually, it arrives at the correct value, so that [exact H] and the overall tactic succeed. *) | 342 (** The tactic first unifies [H] with [H1], as before, but [exact H] fails in that case, so the tactic engine searches for more possible values of [H]. Eventually, it arrives at the correct value, so that [exact H] and the overall tactic succeed. *) |
313 | 343 |
314 (** Now we are equipped to implement a tactic for checking that a proposition is not among our hypotheses: *) | 344 (** Now we are equipped to implement a tactic for checking that a proposition is not among our hypotheses: *) |
315 | 345 |
346 (* begin thide *) | |
316 Ltac notHyp P := | 347 Ltac notHyp P := |
317 match goal with | 348 match goal with |
318 | [ _ : P |- _ ] => fail 1 | 349 | [ _ : P |- _ ] => fail 1 |
319 | _ => | 350 | _ => |
320 match P with | 351 match P with |
321 | ?P1 /\ ?P2 => first [ notHyp P1 | notHyp P2 | fail 2 ] | 352 | ?P1 /\ ?P2 => first [ notHyp P1 | notHyp P2 | fail 2 ] |
322 | _ => idtac | 353 | _ => idtac |
323 end | 354 end |
324 end. | 355 end. |
356 (* end thide *) | |
325 | 357 |
326 (** We use the equality checking that is built into pattern-matching to see if there is a hypothesis that matches the proposition exactly. If so, we use the [fail] tactic. Without arguments, [fail] signals normal tactic failure, as you might expect. When [fail] is passed an argument [n], [n] is used to count outwards through the enclosing cases of backtracking search. In this case, [fail 1] says "fail not just in this pattern-matching branch, but for the whole [match]." The second case will never be tried when the [fail 1] is reached. | 358 (** We use the equality checking that is built into pattern-matching to see if there is a hypothesis that matches the proposition exactly. If so, we use the [fail] tactic. Without arguments, [fail] signals normal tactic failure, as you might expect. When [fail] is passed an argument [n], [n] is used to count outwards through the enclosing cases of backtracking search. In this case, [fail 1] says "fail not just in this pattern-matching branch, but for the whole [match]." The second case will never be tried when the [fail 1] is reached. |
327 | 359 |
328 This second case, used when [P] matches no hypothesis, checks if [P] is a conjunction. Other simplifications may have split conjunctions into their component formulas, so we need to check that at least one of those components is also not represented. To achieve this, we apply the [first] tactical, which takes a list of tactics and continues down the list until one of them does not fail. The [fail 2] at the end says to [fail] both the [first] and the [match] wrapped around it. | 360 This second case, used when [P] matches no hypothesis, checks if [P] is a conjunction. Other simplifications may have split conjunctions into their component formulas, so we need to check that at least one of those components is also not represented. To achieve this, we apply the [first] tactical, which takes a list of tactics and continues down the list until one of them does not fail. The [fail 2] at the end says to [fail] both the [first] and the [match] wrapped around it. |
329 | 361 |
330 The body of the [?P1 /\ ?P2] case guarantees that, if it is reached, we either succeed completely or fail completely. Thus, if we reach the wildcard case, [P] is not a conjunction. We use [idtac], a tactic that would be silly to apply on its own, since its effect is to succeed at doing nothing. Nonetheless, [idtac] is a useful placeholder for cases like what we see here. | 362 The body of the [?P1 /\ ?P2] case guarantees that, if it is reached, we either succeed completely or fail completely. Thus, if we reach the wildcard case, [P] is not a conjunction. We use [idtac], a tactic that would be silly to apply on its own, since its effect is to succeed at doing nothing. Nonetheless, [idtac] is a useful placeholder for cases like what we see here. |
331 | 363 |
332 With the non-presence check implemented, it is easy to build a tactic that takes as input a proof term and adds its conclusion as a new hypothesis, only if that conclusion is not already present, failing otherwise. *) | 364 With the non-presence check implemented, it is easy to build a tactic that takes as input a proof term and adds its conclusion as a new hypothesis, only if that conclusion is not already present, failing otherwise. *) |
333 | 365 |
366 (* begin thide *) | |
334 Ltac extend pf := | 367 Ltac extend pf := |
335 let t := type of pf in | 368 let t := type of pf in |
336 notHyp t; generalize pf; intro. | 369 notHyp t; generalize pf; intro. |
370 (* end thide *) | |
337 | 371 |
338 (** We see the useful [type of] operator of Ltac. This operator could not be implemented in Gallina, but it is easy to support in Ltac. We end up with [t] bound to the type of [pf]. We check that [t] is not already present. If so, we use a [generalize]/[intro] combo to add a new hypothesis proved by [pf]. | 372 (** We see the useful [type of] operator of Ltac. This operator could not be implemented in Gallina, but it is easy to support in Ltac. We end up with [t] bound to the type of [pf]. We check that [t] is not already present. If so, we use a [generalize]/[intro] combo to add a new hypothesis proved by [pf]. |
339 | 373 |
340 With these tactics defined, we can write a tactic [completer] for adding to the context all consequences of a set of simple first-order formulas. *) | 374 With these tactics defined, we can write a tactic [completer] for adding to the context all consequences of a set of simple first-order formulas. *) |
341 | 375 |
376 (* begin thide *) | |
342 Ltac completer := | 377 Ltac completer := |
343 repeat match goal with | 378 repeat match goal with |
344 | [ |- _ /\ _ ] => constructor | 379 | [ |- _ /\ _ ] => constructor |
345 | [ H : _ /\ _ |- _ ] => destruct H | 380 | [ H : _ /\ _ |- _ ] => destruct H |
346 | [ H : ?P -> ?Q, H' : ?P |- _ ] => | 381 | [ H : ?P -> ?Q, H' : ?P |- _ ] => |
348 | [ |- forall x, _ ] => intro | 383 | [ |- forall x, _ ] => intro |
349 | 384 |
350 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] => | 385 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] => |
351 extend (H X H') | 386 extend (H X H') |
352 end. | 387 end. |
388 (* end thide *) | |
353 | 389 |
354 (** We use the same kind of conjunction and implication handling as previously. Note that, since [->] is the special non-dependent case of [forall], the fourth rule handles [intro] for implications, too. | 390 (** We use the same kind of conjunction and implication handling as previously. Note that, since [->] is the special non-dependent case of [forall], the fourth rule handles [intro] for implications, too. |
355 | 391 |
356 In the fifth rule, when we find a [forall] fact [H] with a premise matching one of our hypotheses, we add the appropriate instantiation of [H]'s conclusion, if we have not already added it. | 392 In the fifth rule, when we find a [forall] fact [H] with a premise matching one of our hypotheses, we add the appropriate instantiation of [H]'s conclusion, if we have not already added it. |
357 | 393 |
363 | 399 |
364 Hypothesis H1 : forall x, P x -> Q x /\ R x. | 400 Hypothesis H1 : forall x, P x -> Q x /\ R x. |
365 Hypothesis H2 : forall x, R x -> S x. | 401 Hypothesis H2 : forall x, R x -> S x. |
366 | 402 |
367 Theorem fo : forall x, P x -> S x. | 403 Theorem fo : forall x, P x -> S x. |
404 (* begin thide *) | |
368 completer. | 405 completer. |
369 (** [[ | 406 (** [[ |
370 | 407 |
371 x : A | 408 x : A |
372 H : P x | 409 H : P x |
377 S x | 414 S x |
378 ]] *) | 415 ]] *) |
379 | 416 |
380 assumption. | 417 assumption. |
381 Qed. | 418 Qed. |
419 (* end thide *) | |
382 End firstorder. | 420 End firstorder. |
383 | 421 |
384 (** We narrowly avoided a subtle pitfall in our definition of [completer]. Let us try another definition that even seems preferable to the original, to the untrained eye. *) | 422 (** We narrowly avoided a subtle pitfall in our definition of [completer]. Let us try another definition that even seems preferable to the original, to the untrained eye. *) |
385 | 423 |
424 (* begin thide *) | |
386 Ltac completer' := | 425 Ltac completer' := |
387 repeat match goal with | 426 repeat match goal with |
388 | [ |- _ /\ _ ] => constructor | 427 | [ |- _ /\ _ ] => constructor |
389 | [ H : _ /\ _ |- _ ] => destruct H | 428 | [ H : _ /\ _ |- _ ] => destruct H |
390 | [ H : ?P -> _, H' : ?P |- _ ] => | 429 | [ H : ?P -> _, H' : ?P |- _ ] => |
392 | [ |- forall x, _ ] => intro | 431 | [ |- forall x, _ ] => intro |
393 | 432 |
394 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] => | 433 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] => |
395 extend (H X H') | 434 extend (H X H') |
396 end. | 435 end. |
436 (* end thide *) | |
397 | 437 |
398 (** The only difference is in the modus ponens rule, where we have replaced an unused unification variable [?Q] with a wildcard. Let us try our example again with this version: *) | 438 (** The only difference is in the modus ponens rule, where we have replaced an unused unification variable [?Q] with a wildcard. Let us try our example again with this version: *) |
399 | 439 |
400 Section firstorder'. | 440 Section firstorder'. |
401 Variable A : Set. | 441 Variable A : Set. |
403 | 443 |
404 Hypothesis H1 : forall x, P x -> Q x /\ R x. | 444 Hypothesis H1 : forall x, P x -> Q x /\ R x. |
405 Hypothesis H2 : forall x, R x -> S x. | 445 Hypothesis H2 : forall x, R x -> S x. |
406 | 446 |
407 Theorem fo' : forall x, P x -> S x. | 447 Theorem fo' : forall x, P x -> S x. |
448 (* begin thide *) | |
408 (** [[ | 449 (** [[ |
409 | 450 |
410 completer'. | 451 completer'. |
411 | 452 |
412 Coq loops forever at this point. What went wrong? *) | 453 Coq loops forever at this point. What went wrong? *) |
413 Abort. | 454 Abort. |
455 (* end thide *) | |
414 End firstorder'. | 456 End firstorder'. |
415 | 457 |
416 (** A few examples should illustrate the issue. Here we see a [match]-based proof that works fine: *) | 458 (** A few examples should illustrate the issue. Here we see a [match]-based proof that works fine: *) |
417 | 459 |
418 Theorem t1 : forall x : nat, x = x. | 460 Theorem t1 : forall x : nat, x = x. |
419 match goal with | 461 match goal with |
420 | [ |- forall x, _ ] => trivial | 462 | [ |- forall x, _ ] => trivial |
421 end. | 463 end. |
422 Qed. | 464 (* begin thide *) |
465 Qed. | |
466 (* end thide *) | |
423 | 467 |
424 (** This one fails. *) | 468 (** This one fails. *) |
425 | 469 |
470 (* begin thide *) | |
426 Theorem t1' : forall x : nat, x = x. | 471 Theorem t1' : forall x : nat, x = x. |
427 (** [[ | 472 (** [[ |
428 | 473 |
429 match goal with | 474 match goal with |
430 | [ |- forall x, ?P ] => trivial | 475 | [ |- forall x, ?P ] => trivial |
432 | 477 |
433 [[ | 478 [[ |
434 User error: No matching clauses for match goal | 479 User error: No matching clauses for match goal |
435 ]] *) | 480 ]] *) |
436 Abort. | 481 Abort. |
482 (* end thide *) | |
437 | 483 |
438 (** The problem is that unification variables may not contain locally-bound variables. In this case, [?P] would need to be bound to [x = x], which contains the local quantified variable [x]. By using a wildcard in the earlier version, we avoided this restriction. | 484 (** The problem is that unification variables may not contain locally-bound variables. In this case, [?P] would need to be bound to [x = x], which contains the local quantified variable [x]. By using a wildcard in the earlier version, we avoided this restriction. |
439 | 485 |
440 The Coq 8.2 release includes a special pattern form for a unification variable with an explicit set of free variables. That unification variable is then bound to a function from the free variables to the "real" value. In Coq 8.1 and earlier, there is no such workaround. | 486 The Coq 8.2 release includes a special pattern form for a unification variable with an explicit set of free variables. That unification variable is then bound to a function from the free variables to the "real" value. In Coq 8.1 and earlier, there is no such workaround. |
441 | 487 |
442 No matter which version you use, it is important to be aware of this restriction. As we have alluded to, the restriction is the culprit behind the infinite-looping behavior of [completer']. We unintentionally match quantified facts with the modus ponens rule, circumventing the "already present" check and leading to different behavior. *) | 488 No matter which version you use, it is important to be aware of this restriction. As we have alluded to, the restriction is the culprit behind the infinite-looping behavior of [completer']. We unintentionally match quantified facts with the modus ponens rule, circumventing the "already present" check and leading to different behavior. *) |
443 | 489 |
444 | 490 |
445 (** * Functional Programming in Ltac *) | 491 (** * Functional Programming in Ltac *) |
492 | |
493 (* EX: Write a list length function in Ltac. *) | |
446 | 494 |
447 (** Ltac supports quite convenient functional programming, with a Lisp-with-syntax kind of flavor. However, there are a few syntactic conventions involved in getting programs to be accepted. The Ltac syntax is optimized for tactic-writing, so one has to deal with some inconveniences in writing more standard functional programs. | 495 (** Ltac supports quite convenient functional programming, with a Lisp-with-syntax kind of flavor. However, there are a few syntactic conventions involved in getting programs to be accepted. The Ltac syntax is optimized for tactic-writing, so one has to deal with some inconveniences in writing more standard functional programs. |
448 | 496 |
449 To illustrate, let us try to write a simple list length function. We start out writing it just like in Gallina, simply replacing [Fixpoint] (and its annotations) with [Ltac]. | 497 To illustrate, let us try to write a simple list length function. We start out writing it just like in Gallina, simply replacing [Fixpoint] (and its annotations) with [Ltac]. |
450 | 498 |
472 Error: The reference S was not found in the current environment | 520 Error: The reference S was not found in the current environment |
473 ]] | 521 ]] |
474 | 522 |
475 The problem is that Ltac treats the expression [S (length ls')] as an invocation of a tactic [S] with argument [length ls']. We need to use a special annotation to "escape into" the Gallina parsing nonterminal. *) | 523 The problem is that Ltac treats the expression [S (length ls')] as an invocation of a tactic [S] with argument [length ls']. We need to use a special annotation to "escape into" the Gallina parsing nonterminal. *) |
476 | 524 |
525 (* begin thide *) | |
477 Ltac length ls := | 526 Ltac length ls := |
478 match ls with | 527 match ls with |
479 | nil => O | 528 | nil => O |
480 | _ :: ?ls' => constr:(S (length ls')) | 529 | _ :: ?ls' => constr:(S (length ls')) |
481 end. | 530 end. |
514 n := 3 : nat | 563 n := 3 : nat |
515 ============================ | 564 ============================ |
516 False | 565 False |
517 ]] *) | 566 ]] *) |
518 Abort. | 567 Abort. |
568 (* end thide *) | |
569 | |
570 (* EX: Write a list map function in Ltac. *) | |
519 | 571 |
520 (** We can also use anonymous function expressions and local function definitions in Ltac, as this example of a standard list [map] function shows. *) | 572 (** We can also use anonymous function expressions and local function definitions in Ltac, as this example of a standard list [map] function shows. *) |
521 | 573 |
574 (* begin thide *) | |
522 Ltac map T f := | 575 Ltac map T f := |
523 let rec map' ls := | 576 let rec map' ls := |
524 match ls with | 577 match ls with |
525 | nil => constr:(@nil T) | 578 | nil => constr:(@nil T) |
526 | ?x :: ?ls' => | 579 | ?x :: ?ls' => |
542 l := (1, 1) :: (2, 2) :: (3, 3) :: nil : list (nat * nat) | 595 l := (1, 1) :: (2, 2) :: (3, 3) :: nil : list (nat * nat) |
543 ============================ | 596 ============================ |
544 False | 597 False |
545 ]] *) | 598 ]] *) |
546 Abort. | 599 Abort. |
600 (* end thide *) | |
547 | 601 |
548 | 602 |
549 (** * Recursive Proof Search *) | 603 (** * Recursive Proof Search *) |
550 | 604 |
551 (** Deciding how to instantiate quantifiers is one of the hardest parts of automated first-order theorem proving. For a given problem, we can consider all possible bounded-length sequences of quantifier instantiations, applying only propositional reasoning at the end. This is probably a bad idea for almost all goals, but it makes for a nice example of recursive proof search procedures in Ltac. | 605 (** Deciding how to instantiate quantifiers is one of the hardest parts of automated first-order theorem proving. For a given problem, we can consider all possible bounded-length sequences of quantifier instantiations, applying only propositional reasoning at the end. This is probably a bad idea for almost all goals, but it makes for a nice example of recursive proof search procedures in Ltac. |
552 | 606 |
553 We can consider the maximum "dependency chain" length for a first-order proof. We define the chain length for a hypothesis to be 0, and the chain length for an instantiation of a quantified fact to be one greater than the length for that fact. The tactic [inster n] is meant to try all possible proofs with chain length at most [n]. *) | 607 We can consider the maximum "dependency chain" length for a first-order proof. We define the chain length for a hypothesis to be 0, and the chain length for an instantiation of a quantified fact to be one greater than the length for that fact. The tactic [inster n] is meant to try all possible proofs with chain length at most [n]. *) |
554 | 608 |
609 (* begin thide *) | |
555 Ltac inster n := | 610 Ltac inster n := |
556 intuition; | 611 intuition; |
557 match n with | 612 match n with |
558 | S ?n' => | 613 | S ?n' => |
559 match goal with | 614 match goal with |
560 | [ H : forall x : ?T, _, x : ?T |- _ ] => generalize (H x); inster n' | 615 | [ H : forall x : ?T, _, x : ?T |- _ ] => generalize (H x); inster n' |
561 end | 616 end |
562 end. | 617 end. |
618 (* end thide *) | |
563 | 619 |
564 (** [inster] begins by applying propositional simplification. Next, it checks if any chain length remains. If so, it tries all possible ways of instantiating quantified hypotheses with properly-typed local variables. It is critical to realize that, if the recursive call [inster n'] fails, then the [match goal] just seeks out another way of unifying its pattern against proof state. Thus, this small amount of code provides an elegant demonstration of how backtracking [match] enables exhaustive search. | 620 (** [inster] begins by applying propositional simplification. Next, it checks if any chain length remains. If so, it tries all possible ways of instantiating quantified hypotheses with properly-typed local variables. It is critical to realize that, if the recursive call [inster n'] fails, then the [match goal] just seeks out another way of unifying its pattern against proof state. Thus, this small amount of code provides an elegant demonstration of how backtracking [match] enables exhaustive search. |
565 | 621 |
566 We can verify the efficacy of [inster] with two short examples. The built-in [firstorder] tactic (with no extra arguments) is able to prove the first but not the second. *) | 622 We can verify the efficacy of [inster] with two short examples. The built-in [firstorder] tactic (with no extra arguments) is able to prove the first but not the second. *) |
567 | 623 |
647 imp. | 703 imp. |
648 Qed. | 704 Qed. |
649 | 705 |
650 (** The first order of business in crafting our [matcher] tactic will be auxiliary support for searching through formula trees. The [search_prem] tactic implements running its tactic argument [tac] on every subformula of an [imp] premise. As it traverses a tree, [search_prem] applies some of the above lemmas to rewrite the goal to bring different subformulas to the head of the goal. That is, for every subformula [P] of the implication premise, we want [P] to "have a turn," where the premise is rearranged into the form [P /\ Q] for some [Q]. The tactic [tac] should expect to see a goal in this form and focus its attention on the first conjunct of the premise. *) | 706 (** The first order of business in crafting our [matcher] tactic will be auxiliary support for searching through formula trees. The [search_prem] tactic implements running its tactic argument [tac] on every subformula of an [imp] premise. As it traverses a tree, [search_prem] applies some of the above lemmas to rewrite the goal to bring different subformulas to the head of the goal. That is, for every subformula [P] of the implication premise, we want [P] to "have a turn," where the premise is rearranged into the form [P /\ Q] for some [Q]. The tactic [tac] should expect to see a goal in this form and focus its attention on the first conjunct of the premise. *) |
651 | 707 |
708 (* begin thide *) | |
652 Ltac search_prem tac := | 709 Ltac search_prem tac := |
653 let rec search P := | 710 let rec search P := |
654 tac | 711 tac |
655 || (apply and_True_prem; tac) | 712 || (apply and_True_prem; tac) |
656 || match P with | 713 || match P with |
729 intros; | 786 intros; |
730 repeat search_prem ltac:(apply False_prem || (apply ex_prem; intro)); | 787 repeat search_prem ltac:(apply False_prem || (apply ex_prem; intro)); |
731 repeat search_conc ltac:(apply True_conc || eapply ex_conc | 788 repeat search_conc ltac:(apply True_conc || eapply ex_conc |
732 || search_prem ltac:(apply Match)); | 789 || search_prem ltac:(apply Match)); |
733 try apply imp_True. | 790 try apply imp_True. |
791 (* end thide *) | |
734 | 792 |
735 (** Our tactic succeeds at proving a simple example. *) | 793 (** Our tactic succeeds at proving a simple example. *) |
736 | 794 |
737 Theorem t2 : forall P Q : Prop, | 795 Theorem t2 : forall P Q : Prop, |
738 Q /\ (P /\ False) /\ P --> P /\ Q. | 796 Q /\ (P /\ False) /\ P --> P /\ Q. |
785 (ex_conc (fun x0 : nat => P x0) x | 843 (ex_conc (fun x0 : nat => P x0) x |
786 (Match (P:=P x) (imp_True (P:=True)))))))) | 844 (Match (P:=P x) (imp_True (P:=True)))))))) |
787 : forall (P : nat -> Prop) (Q : Prop), | 845 : forall (P : nat -> Prop) (Q : Prop), |
788 (exists x : nat, P x /\ Q) --> Q /\ (exists x : nat, P x) | 846 (exists x : nat, P x /\ Q) --> Q /\ (exists x : nat, P x) |
789 ]] *) | 847 ]] *) |
790 | |
791 |