42 apply(assumption) |
42 apply(assumption) |
43 apply(rule disjI1) |
43 apply(rule disjI1) |
44 apply(assumption) |
44 apply(assumption) |
45 done |
45 done |
46 |
46 |
47 |
|
48 |
|
49 text {* |
47 text {* |
50 This proof translates to the following ML-code. |
48 This proof translates to the following ML-code. |
51 |
49 |
52 @{ML_response_fake [display,gray] |
50 @{ML_response_fake [display,gray] |
53 "let |
51 "let |
54 val ctxt = @{context} |
52 val ctxt = @{context} |
55 val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"} |
53 val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"} |
56 in |
54 in |
57 Goal.prove ctxt [\"P\", \"Q\"] [] goal |
55 Goal.prove ctxt [\"P\", \"Q\"] [] goal |
58 (fn _ => etac @{thm disjE} 1 |
56 (fn _ => eresolve_tac @{context} [@{thm disjE}] 1 |
59 THEN rtac @{thm disjI2} 1 |
57 THEN resolve_tac @{context} [@{thm disjI2}] 1 |
60 THEN atac 1 |
58 THEN assume_tac @{context} 1 |
61 THEN rtac @{thm disjI1} 1 |
59 THEN resolve_tac @{context} [@{thm disjI1}] 1 |
62 THEN atac 1) |
60 THEN assume_tac @{context} 1) |
63 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
61 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
64 |
62 |
65 To start the proof, the function @{ML_ind prove in Goal} sets up a goal |
63 To start the proof, the function @{ML_ind prove in Goal} sets up a goal |
66 state for proving the goal @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. We can give this |
64 state for proving the goal @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. We can give this |
67 function some assumptions in the third argument (there are no assumption in |
65 function some assumptions in the third argument (there are no assumption in |
68 the proof at hand). The second argument stands for a list of variables |
66 the proof at hand). The second argument stands for a list of variables |
69 (given as strings). This list contains the variables that will be turned |
67 (given as strings). This list contains the variables that will be turned |
70 into schematic variables once the goal is proved (in our case @{text P} and |
68 into schematic variables once the goal is proved (in our case @{text P} and |
71 @{text Q}). The last argument is the tactic that proves the goal. This |
69 @{text Q}). The last argument is the tactic that proves the goal. This |
72 tactic can make use of the local assumptions (there are none in this |
70 tactic can make use of the local assumptions (there are none in this |
73 example). The tactics @{ML_ind etac in Tactic}, @{ML_ind rtac in Tactic} and |
71 example). The tactics @{ML_ind eresolve_tac in Tactic}, @{ML_ind resolve_tac in Tactic} and |
74 @{ML_ind atac in Tactic} in the code above correspond roughly to @{text |
72 @{ML_ind assume_tac in Tactic} in the code above correspond roughly to @{text |
75 erule}, @{text rule} and @{text assumption}, respectively. The combinator |
73 erule}, @{text rule} and @{text assumption}, respectively. The combinator |
76 @{ML THEN} strings the tactics together. |
74 @{ML THEN} strings the tactics together. |
77 |
75 |
78 TBD: Write something about @{ML_ind prove_multi in Goal}. |
76 TBD: Write something about @{ML_ind prove_common in Goal}. |
79 |
77 |
80 \begin{readmore} |
78 \begin{readmore} |
81 To learn more about the function @{ML_ind prove in Goal} see |
79 To learn more about the function @{ML_ind prove in Goal} see |
82 \isccite{sec:results} and the file @{ML_file "Pure/goal.ML"}. See @{ML_file |
80 \isccite{sec:results} and the file @{ML_file "Pure/goal.ML"}. See @{ML_file |
83 "Pure/tactic.ML"} and @{ML_file "Pure/tactical.ML"} for the code of basic |
81 "Pure/tactic.ML"} and @{ML_file "Pure/tactical.ML"} for the code of basic |
94 the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
92 the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
95 Consider the following sequence of tactics |
93 Consider the following sequence of tactics |
96 |
94 |
97 *} |
95 *} |
98 |
96 |
99 ML %grayML{*val foo_tac = |
97 ML %grayML{*fun foo_tac ctxt = |
100 (etac @{thm disjE} 1 |
98 (eresolve_tac ctxt [@{thm disjE}] 1 |
101 THEN rtac @{thm disjI2} 1 |
99 THEN resolve_tac ctxt [@{thm disjI2}] 1 |
102 THEN atac 1 |
100 THEN assume_tac ctxt 1 |
103 THEN rtac @{thm disjI1} 1 |
101 THEN resolve_tac ctxt [@{thm disjI1}] 1 |
104 THEN atac 1)*} |
102 THEN assume_tac ctxt 1)*} |
105 |
103 |
106 text {* and the Isabelle proof: *} |
104 text {* and the Isabelle proof: *} |
107 |
105 |
108 lemma |
106 lemma |
109 shows "P \<or> Q \<Longrightarrow> Q \<or> P" |
107 shows "P \<or> Q \<Longrightarrow> Q \<or> P" |
110 apply(tactic {* foo_tac *}) |
108 apply(tactic {* foo_tac @{context} *}) |
111 done |
109 done |
112 |
110 |
113 text {* |
111 text {* |
114 By using @{text "tactic \<verbopen> \<dots> \<verbclose>"} you can call from the |
112 By using @{text "tactic \<verbopen> \<dots> \<verbclose>"} you can call from the |
115 user-level of Isabelle the tactic @{ML foo_tac} or |
113 user-level of Isabelle the tactic @{ML foo_tac} or |
123 tactic (@{text "1"} stands for the first, or top-most, subgoal). This hard-coding |
121 tactic (@{text "1"} stands for the first, or top-most, subgoal). This hard-coding |
124 of goals is sometimes wanted, but usually it is not. To avoid the explicit numbering, |
122 of goals is sometimes wanted, but usually it is not. To avoid the explicit numbering, |
125 you can write |
123 you can write |
126 *} |
124 *} |
127 |
125 |
128 ML %grayML{*val foo_tac' = |
126 ML %grayML{*fun foo_tac' ctxt = |
129 (etac @{thm disjE} |
127 (eresolve_tac ctxt [@{thm disjE}] |
130 THEN' rtac @{thm disjI2} |
128 THEN' resolve_tac ctxt [@{thm disjI2}] |
131 THEN' atac |
129 THEN' assume_tac ctxt |
132 THEN' rtac @{thm disjI1} |
130 THEN' resolve_tac ctxt [@{thm disjI1}] |
133 THEN' atac)*}text_raw{*\label{tac:footacprime}*} |
131 THEN' assume_tac ctxt)*}text_raw{*\label{tac:footacprime}*} |
134 |
132 |
135 text {* |
133 text {* |
136 where @{ML_ind THEN' in Tactical} is used instead of @{ML THEN in |
134 where @{ML_ind THEN' in Tactical} is used instead of @{ML THEN in |
137 Tactical}. (For most combinators that combine tactics---@{ML THEN} is only |
135 Tactical}. (For most combinators that combine tactics---@{ML THEN} is only |
138 one such combinator---a ``primed'' version exists.) With @{ML foo_tac'} you |
136 one such combinator---a ``primed'' version exists.) With @{ML foo_tac'} you |
405 sometimes useful during the development of tactics. |
403 sometimes useful during the development of tactics. |
406 *} |
404 *} |
407 |
405 |
408 lemma |
406 lemma |
409 shows "False" and "Goldbach_conjecture" |
407 shows "False" and "Goldbach_conjecture" |
410 apply(tactic {* Skip_Proof.cheat_tac 1 *}) |
408 apply(tactic {* Skip_Proof.cheat_tac @{context} 1 *}) |
411 txt{*\begin{minipage}{\textwidth} |
409 txt{*\begin{minipage}{\textwidth} |
412 @{subgoals [display]} |
410 @{subgoals [display]} |
413 \end{minipage}*} |
411 \end{minipage}*} |
414 (*<*)oops(*>*) |
412 (*<*)oops(*>*) |
415 |
413 |
416 text {* |
414 text {* |
417 Another simple tactic is the function @{ML_ind atac in Tactic}, which, as shown |
415 Another simple tactic is the function @{ML_ind assume_tac in Tactic}, which, as shown |
418 earlier, corresponds to the assumption method. |
416 earlier, corresponds to the assumption method. |
419 *} |
417 *} |
420 |
418 |
421 lemma |
419 lemma |
422 shows "P \<Longrightarrow> P" |
420 shows "P \<Longrightarrow> P" |
423 apply(tactic {* atac 1 *}) |
421 apply(tactic {* assume_tac @{context} 1 *}) |
424 txt{*\begin{minipage}{\textwidth} |
422 txt{*\begin{minipage}{\textwidth} |
425 @{subgoals [display]} |
423 @{subgoals [display]} |
426 \end{minipage}*} |
424 \end{minipage}*} |
427 (*<*)oops(*>*) |
425 (*<*)oops(*>*) |
428 |
426 |
429 text {* |
427 text {* |
430 Similarly, @{ML_ind rtac in Tactic}, @{ML_ind dtac in Tactic}, @{ML_ind etac |
428 Similarly, @{ML_ind resolve_tac in Tactic}, @{ML_ind dresolve_tac in Tactic}, @{ML_ind eresolve_tac |
431 in Tactic} and @{ML_ind ftac in Tactic} correspond (roughly) to @{text |
429 in Tactic} and @{ML_ind forward_tac in Tactic} correspond (roughly) to @{text |
432 rule}, @{text drule}, @{text erule} and @{text frule}, respectively. Each of |
430 rule}, @{text drule}, @{text erule} and @{text frule}, respectively. Each of |
433 them takes a theorem as argument and attempts to apply it to a goal. Below |
431 them takes a theorem as argument and attempts to apply it to a goal. Below |
434 are three self-explanatory examples. |
432 are three self-explanatory examples. |
435 *} |
433 *} |
436 |
434 |
437 lemma |
435 lemma |
438 shows "P \<and> Q" |
436 shows "P \<and> Q" |
439 apply(tactic {* rtac @{thm conjI} 1 *}) |
437 apply(tactic {* resolve_tac @{context} [@{thm conjI}] 1 *}) |
440 txt{*\begin{minipage}{\textwidth} |
438 txt{*\begin{minipage}{\textwidth} |
441 @{subgoals [display]} |
439 @{subgoals [display]} |
442 \end{minipage}*} |
440 \end{minipage}*} |
443 (*<*)oops(*>*) |
441 (*<*)oops(*>*) |
444 |
442 |
445 lemma |
443 lemma |
446 shows "P \<and> Q \<Longrightarrow> False" |
444 shows "P \<and> Q \<Longrightarrow> False" |
447 apply(tactic {* etac @{thm conjE} 1 *}) |
445 apply(tactic {* eresolve_tac @{context} [@{thm conjE}] 1 *}) |
448 txt{*\begin{minipage}{\textwidth} |
446 txt{*\begin{minipage}{\textwidth} |
449 @{subgoals [display]} |
447 @{subgoals [display]} |
450 \end{minipage}*} |
448 \end{minipage}*} |
451 (*<*)oops(*>*) |
449 (*<*)oops(*>*) |
452 |
450 |
453 lemma |
451 lemma |
454 shows "False \<and> True \<Longrightarrow> False" |
452 shows "False \<and> True \<Longrightarrow> False" |
455 apply(tactic {* dtac @{thm conjunct2} 1 *}) |
453 apply(tactic {* dresolve_tac @{context} [@{thm conjunct2}] 1 *}) |
456 txt{*\begin{minipage}{\textwidth} |
454 txt{*\begin{minipage}{\textwidth} |
457 @{subgoals [display]} |
455 @{subgoals [display]} |
458 \end{minipage}*} |
456 \end{minipage}*} |
459 (*<*)oops(*>*) |
457 (*<*)oops(*>*) |
460 |
458 |
461 text {* |
459 text {* |
462 The function @{ML_ind resolve_tac in Tactic} is similar to @{ML rtac}, except that it |
460 The function @{ML_ind resolve_tac in Tactic} |
463 expects a list of theorems as argument. From this list it will apply the |
461 expects a list of theorems as argument. From this list it will apply the |
464 first applicable theorem (later theorems that are also applicable can be |
462 first applicable theorem (later theorems that are also applicable can be |
465 explored via the lazy sequences mechanism). Given the code |
463 explored via the lazy sequences mechanism). Given the code |
466 *} |
464 *} |
467 |
465 |
468 ML %grayML{*val resolve_xmp_tac = resolve_tac [@{thm impI}, @{thm conjI}]*} |
466 ML %grayML{*fun resolve_xmp_tac ctxt = resolve_tac ctxt [@{thm impI}, @{thm conjI}]*} |
469 |
467 |
470 text {* |
468 text {* |
471 an example for @{ML resolve_tac} is the following proof where first an outermost |
469 an example for @{ML resolve_tac} is the following proof where first an outermost |
472 implication is analysed and then an outermost conjunction. |
470 implication is analysed and then an outermost conjunction. |
473 *} |
471 *} |
474 |
472 |
475 lemma |
473 lemma |
476 shows "C \<longrightarrow> (A \<and> B)" |
474 shows "C \<longrightarrow> (A \<and> B)" |
477 and "(A \<longrightarrow> B) \<and> C" |
475 and "(A \<longrightarrow> B) \<and> C" |
478 apply(tactic {* resolve_xmp_tac 1 *}) |
476 apply(tactic {* resolve_xmp_tac @{context} 1 *}) |
479 apply(tactic {* resolve_xmp_tac 2 *}) |
477 apply(tactic {* resolve_xmp_tac @{context} 2 *}) |
480 txt{*\begin{minipage}{\textwidth} |
478 txt{*\begin{minipage}{\textwidth} |
481 @{subgoals [display]} |
479 @{subgoals [display]} |
482 \end{minipage}*} |
480 \end{minipage}*} |
483 (*<*)oops(*>*) |
481 (*<*)oops(*>*) |
484 |
482 |
485 text {* |
483 text {* |
486 Similar versions taking a list of theorems exist for the tactics |
484 Similar versions taking a list of theorems exist for the tactics |
487 @{ML dtac} (@{ML_ind dresolve_tac in Tactic}), @{ML etac} |
485 @{ML_ind dresolve_tac in Tactic}, |
488 (@{ML_ind eresolve_tac in Tactic}) and so on. |
486 @{ML_ind eresolve_tac in Tactic} and so on. |
489 |
487 |
490 Another simple tactic is @{ML_ind cut_facts_tac in Tactic}. It inserts a |
488 Another simple tactic is @{ML_ind cut_facts_tac in Tactic}. It inserts a |
491 list of theorems into the assumptions of the current goal state. Below we |
489 list of theorems into the assumptions of the current goal state. Below we |
492 will insert the definitions for the constants @{term True} and @{term |
490 will insert the definitions for the constants @{term True} and @{term |
493 False}. So |
491 False}. So |
519 \begin{figure}[t] |
517 \begin{figure}[t] |
520 \begin{minipage}{\textwidth} |
518 \begin{minipage}{\textwidth} |
521 \begin{isabelle} |
519 \begin{isabelle} |
522 *} |
520 *} |
523 |
521 |
524 ML %grayML{*fun foc_tac {prems, params, asms, concl, context, schematics} = |
522 ML %grayML{*fun foc_tac {context, params, prems, asms, concl, schematics} = |
525 let |
523 let |
526 fun assgn1 f1 f2 xs = |
524 fun assgn1 f1 f2 xs = |
527 let |
525 let |
528 val out = map (fn (x, y) => Pretty.enum ":=" "" "" [f1 x, f2 y]) xs |
526 val out = map (fn (x, y) => Pretty.enum ":=" "" "" [f1 x, f2 y]) xs |
529 in |
527 in |
530 Pretty.list "" "" out |
528 Pretty.list "" "" out |
531 end |
529 end |
532 |
530 |
533 fun assgn2 f xs = assgn1 f f xs |
531 fun assgn2 f xs = assgn1 (fn (n,T) => pretty_term context (Var (n,T))) f xs |
534 |
532 |
535 val pps = map (fn (s, pp) => Pretty.block [Pretty.str s, pp]) |
533 val pps = map (fn (s, pp) => Pretty.block [Pretty.str s, pp]) |
536 [("params: ", assgn1 Pretty.str (pretty_cterm context) params), |
534 [("params: ", assgn1 Pretty.str (pretty_cterm context) params), |
537 ("assumptions: ", pretty_cterms context asms), |
535 ("assumptions: ", pretty_cterms context asms), |
538 ("conclusion: ", pretty_cterm context concl), |
536 ("conclusion: ", pretty_cterm context concl), |
606 is that the former expects that the goal is solved completely, which the |
604 is that the former expects that the goal is solved completely, which the |
607 latter does not. Another is that @{ML SUBPROOF} cannot instantiate any schematic |
605 latter does not. Another is that @{ML SUBPROOF} cannot instantiate any schematic |
608 variables. |
606 variables. |
609 |
607 |
610 Observe that inside @{ML FOCUS in Subgoal} and @{ML SUBPROOF}, we are in a goal |
608 Observe that inside @{ML FOCUS in Subgoal} and @{ML SUBPROOF}, we are in a goal |
611 state where there is only a conclusion. This means the tactics @{ML dtac} and |
609 state where there is only a conclusion. This means the tactics @{ML dresolve_tac} and |
612 the like are of no use for manipulating the goal state. The assumptions inside |
610 the like are of no use for manipulating the goal state. The assumptions inside |
613 @{ML FOCUS in Subgoal} and @{ML SUBPROOF} are given as cterms and theorems in |
611 @{ML FOCUS in Subgoal} and @{ML SUBPROOF} are given as cterms and theorems in |
614 the arguments @{text "asms"} and @{text "prems"}, respectively. This |
612 the arguments @{text "asms"} and @{text "prems"}, respectively. This |
615 means we can apply them using the usual assumption tactics. With this you can |
613 means we can apply them using the usual assumption tactics. With this you can |
616 for example easily implement a tactic that behaves almost like @{ML atac}: |
614 for example easily implement a tactic that behaves almost like @{ML assume_tac}: |
617 *} |
615 *} |
618 |
616 |
619 ML %grayML{*val atac' = Subgoal.FOCUS (fn {prems, ...} => resolve_tac prems 1)*} |
617 ML %grayML{*val atac' = Subgoal.FOCUS (fn {prems, context, ...} => resolve_tac context prems 1)*} |
620 |
618 |
621 text {* |
619 text {* |
622 If you apply @{ML atac'} to the next lemma |
620 If you apply @{ML atac'} to the next lemma |
623 *} |
621 *} |
624 |
622 |
667 cterm}). With them you can implement a tactic that applies a rule according |
665 cterm}). With them you can implement a tactic that applies a rule according |
668 to the topmost logic connective in the subgoal (to illustrate this we only |
666 to the topmost logic connective in the subgoal (to illustrate this we only |
669 analyse a few connectives). The code of the tactic is as follows. |
667 analyse a few connectives). The code of the tactic is as follows. |
670 *} |
668 *} |
671 |
669 |
672 ML %linenosgray{*fun select_tac (t, i) = |
670 ML %linenosgray{*fun select_tac ctxt (t, i) = |
673 case t of |
671 case t of |
674 @{term "Trueprop"} $ t' => select_tac (t', i) |
672 @{term "Trueprop"} $ t' => select_tac ctxt (t', i) |
675 | @{term "op \<Longrightarrow>"} $ _ $ t' => select_tac (t', i) |
673 | @{term "(\<Longrightarrow>)"} $ _ $ t' => select_tac ctxt (t', i) |
676 | @{term "op \<and>"} $ _ $ _ => rtac @{thm conjI} i |
674 | @{term "(\<and>)"} $ _ $ _ => resolve_tac ctxt [@{thm conjI}] i |
677 | @{term "op \<longrightarrow>"} $ _ $ _ => rtac @{thm impI} i |
675 | @{term "(\<longrightarrow>)"} $ _ $ _ => resolve_tac ctxt [@{thm impI}] i |
678 | @{term "Not"} $ _ => rtac @{thm notI} i |
676 | @{term "Not"} $ _ => resolve_tac ctxt [@{thm notI}] i |
679 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
677 | Const (@{const_name "All"}, _) $ _ => resolve_tac ctxt [@{thm allI}] i |
680 | _ => all_tac*}text_raw{*\label{tac:selecttac}*} |
678 | _ => all_tac*}text_raw{*\label{tac:selecttac}*} |
681 |
679 |
682 text {* |
680 text {* |
683 The input of the function is a term representing the subgoal and a number |
681 The input of the function is a term representing the subgoal and a number |
684 specifying the subgoal of interest. In Line 3 you need to descend under the |
682 specifying the subgoal of interest. In Line 3 you need to descend under the |
741 \begin{readmore} |
739 \begin{readmore} |
742 The functions @{ML SUBGOAL} and @{ML CSUBGOAL} are defined in @{ML_file "Pure/tactical.ML"}. |
740 The functions @{ML SUBGOAL} and @{ML CSUBGOAL} are defined in @{ML_file "Pure/tactical.ML"}. |
743 \end{readmore} |
741 \end{readmore} |
744 |
742 |
745 |
743 |
746 Since @{ML_ind rtac in Tactic} and the like use higher-order unification, an |
744 Since @{ML_ind resolve_tac in Tactic} and the like use higher-order unification, an |
747 automatic proof procedure based on them might become too fragile, if it just |
745 automatic proof procedure based on them might become too fragile, if it just |
748 applies theorems as shown above. The reason is that a number of theorems |
746 applies theorems as shown above. The reason is that a number of theorems |
749 introduce schematic variables into the goal state. Consider for example the |
747 introduce schematic variables into the goal state. Consider for example the |
750 proof |
748 proof |
751 *} |
749 *} |
752 |
750 |
753 lemma |
751 lemma |
754 shows "\<forall>x \<in> A. P x \<Longrightarrow> Q x" |
752 shows "\<forall>x \<in> A. P x \<Longrightarrow> Q x" |
755 apply(tactic {* dtac @{thm bspec} 1 *}) |
753 apply(tactic {* dresolve_tac @{context} [@{thm bspec}] 1 *}) |
756 txt{*\begin{minipage}{\textwidth} |
754 txt{*\begin{minipage}{\textwidth} |
757 @{subgoals [display]} |
755 @{subgoals [display]} |
758 \end{minipage}*} |
756 \end{minipage}*} |
759 (*<*)oops(*>*) |
757 (*<*)oops(*>*) |
760 |
758 |
879 that can be used to instantiate the theorem. The instantiation |
877 that can be used to instantiate the theorem. The instantiation |
880 can be done with the function @{ML_ind instantiate_normalize in Drule}. To automate |
878 can be done with the function @{ML_ind instantiate_normalize in Drule}. To automate |
881 this we implement the following function. |
879 this we implement the following function. |
882 *} |
880 *} |
883 |
881 |
884 ML %linenosgray{*fun fo_rtac thm = Subgoal.FOCUS (fn {concl, ...} => |
882 ML %linenosgray{*fun fo_rtac thm = Subgoal.FOCUS (fn {context, concl, ...} => |
885 let |
883 let |
886 val concl_pat = Drule.strip_imp_concl (cprop_of thm) |
884 val concl_pat = Drule.strip_imp_concl (Thm.cprop_of thm) |
887 val insts = Thm.first_order_match (concl_pat, concl) |
885 val insts = Thm.first_order_match (concl_pat, concl) |
888 in |
886 in |
889 rtac (Drule.instantiate_normalize insts thm) 1 |
887 resolve_tac context [(Drule.instantiate_normalize insts thm)] 1 |
890 end)*} |
888 end)*} |
891 |
889 |
892 text {* |
890 text {* |
893 Note that we use @{ML FOCUS in Subgoal} because it gives us directly access |
891 Note that we use @{ML FOCUS in Subgoal} because it gives us directly access |
894 to the conclusion of the goal state, but also because this function |
892 to the conclusion of the goal state, but also because this function |
976 one specified subgoal, you can use the combinator @{ML_ind EVERY' in |
974 one specified subgoal, you can use the combinator @{ML_ind EVERY' in |
977 Tactical}. For example the function @{ML foo_tac'} from |
975 Tactical}. For example the function @{ML foo_tac'} from |
978 page~\pageref{tac:footacprime} can also be written as: |
976 page~\pageref{tac:footacprime} can also be written as: |
979 *} |
977 *} |
980 |
978 |
981 ML %grayML{*val foo_tac'' = EVERY' [etac @{thm disjE}, rtac @{thm disjI2}, |
979 ML %grayML{*fun foo_tac'' ctxt = |
982 atac, rtac @{thm disjI1}, atac]*} |
980 EVERY' [eresolve_tac ctxt [@{thm disjE}], resolve_tac ctxt [@{thm disjI2}], |
|
981 assume_tac ctxt, resolve_tac ctxt [@{thm disjI1}], assume_tac ctxt]*} |
983 |
982 |
984 text {* |
983 text {* |
985 There is even another way of implementing this tactic: in automatic proof |
984 There is even another way of implementing this tactic: in automatic proof |
986 procedures (in contrast to tactics that might be called by the user) there |
985 procedures (in contrast to tactics that might be called by the user) there |
987 are often long lists of tactics that are applied to the first |
986 are often long lists of tactics that are applied to the first |
988 subgoal. Instead of writing the code above and then calling @{ML "foo_tac'' 1"}, |
987 subgoal. Instead of writing the code above and then calling @{ML "foo_tac'' @{context} 1"}, |
989 you can also just write |
988 you can also just write |
990 *} |
989 *} |
991 |
990 |
992 ML %grayML{*val foo_tac1 = EVERY1 [etac @{thm disjE}, rtac @{thm disjI2}, |
991 ML %grayML{*fun foo_tac1 ctxt = |
993 atac, rtac @{thm disjI1}, atac]*} |
992 EVERY1 [eresolve_tac ctxt [@{thm disjE}], resolve_tac ctxt [@{thm disjI2}], |
|
993 assume_tac ctxt, resolve_tac ctxt [@{thm disjI1}], assume_tac ctxt]*} |
994 |
994 |
995 text {* |
995 text {* |
996 and call @{ML foo_tac1}. |
996 and call @{ML foo_tac1}. |
997 |
997 |
998 With the combinators @{ML THEN'}, @{ML EVERY'} and @{ML_ind EVERY1 in Tactical} it must be |
998 With the combinators @{ML THEN'}, @{ML EVERY'} and @{ML_ind EVERY1 in Tactical} it must be |
1001 then you can use the combinator @{ML_ind ORELSE' in Tactical} for two tactics, and @{ML_ind |
1001 then you can use the combinator @{ML_ind ORELSE' in Tactical} for two tactics, and @{ML_ind |
1002 FIRST' in Tactical} (or @{ML_ind FIRST1 in Tactical}) for a list of tactics. For example, the tactic |
1002 FIRST' in Tactical} (or @{ML_ind FIRST1 in Tactical}) for a list of tactics. For example, the tactic |
1003 |
1003 |
1004 *} |
1004 *} |
1005 |
1005 |
1006 ML %grayML{*val orelse_xmp_tac = rtac @{thm disjI1} ORELSE' rtac @{thm conjI}*} |
1006 ML %grayML{*fun orelse_xmp_tac ctxt = |
|
1007 resolve_tac ctxt [@{thm disjI1}] ORELSE' resolve_tac ctxt [@{thm conjI}]*} |
1007 |
1008 |
1008 text {* |
1009 text {* |
1009 will first try out whether theorem @{text disjI} applies and in case of failure |
1010 will first try out whether theorem @{text disjI} applies and in case of failure |
1010 will try @{text conjI}. To see this consider the proof |
1011 will try @{text conjI}. To see this consider the proof |
1011 *} |
1012 *} |
1012 |
1013 |
1013 lemma |
1014 lemma |
1014 shows "True \<and> False" and "Foo \<or> Bar" |
1015 shows "True \<and> False" and "Foo \<or> Bar" |
1015 apply(tactic {* orelse_xmp_tac 2 *}) |
1016 apply(tactic {* orelse_xmp_tac @{context} 2 *}) |
1016 apply(tactic {* orelse_xmp_tac 1 *}) |
1017 apply(tactic {* orelse_xmp_tac @{context} 1 *}) |
1017 txt {* which results in the goal state |
1018 txt {* which results in the goal state |
1018 \begin{isabelle} |
1019 \begin{isabelle} |
1019 @{subgoals [display]} |
1020 @{subgoals [display]} |
1020 \end{isabelle} |
1021 \end{isabelle} |
1021 *} |
1022 *} |
1432 |
1435 |
1433 fun name_sthm (nm, thm) = |
1436 fun name_sthm (nm, thm) = |
1434 Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm] |
1437 Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm] |
1435 fun name_cthm ((_, nm), thm) = |
1438 fun name_cthm ((_, nm), thm) = |
1436 Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm] |
1439 Pretty.enclose (nm ^ ": ") "" [pretty_thm_no_vars ctxt thm] |
1437 fun name_ctrm (nm, ctrm) = |
1440 fun name_trm (nm, trm) = |
1438 Pretty.enclose (nm ^ ": ") "" [pretty_cterms ctxt ctrm] |
1441 Pretty.enclose (nm ^ ": ") "" [pretty_terms ctxt trm] |
1439 |
1442 |
1440 val pps = [Pretty.big_list "Simplification rules:" (map name_sthm simps), |
1443 val pps = [Pretty.big_list "Simplification rules:" (map name_sthm simps), |
1441 Pretty.big_list "Congruences rules:" (map name_cthm congs), |
1444 Pretty.big_list "Congruences rules:" (map name_cthm congs), |
1442 Pretty.big_list "Simproc patterns:" (map name_ctrm procs)] |
1445 Pretty.big_list "Simproc patterns:" (map name_trm procs)] |
1443 in |
1446 in |
1444 pps |> Pretty.chunks |
1447 pps |> Pretty.chunks |
1445 |> pwriteln |
1448 |> pwriteln |
1446 end*} |
1449 end*} |
1447 text_raw {* |
1450 text_raw {* |
1844 want this, then you have to use a slightly different method for setting |
1847 want this, then you have to use a slightly different method for setting |
1845 up the simproc. First the function @{ML fail_simproc} needs to be modified |
1848 up the simproc. First the function @{ML fail_simproc} needs to be modified |
1846 to |
1849 to |
1847 *} |
1850 *} |
1848 |
1851 |
1849 ML %grayML{*fun fail_simproc' ctxt redex = |
1852 ML %grayML{*fun fail_simproc' _ ctxt redex = |
1850 let |
1853 let |
1851 val _ = pwriteln (Pretty.block |
1854 val _ = pwriteln (Pretty.block |
1852 [Pretty.str "The redex:", pretty_term ctxt redex]) |
1855 [Pretty.str "The redex:", pretty_cterm ctxt redex]) |
1853 in |
1856 in |
1854 NONE |
1857 NONE |
1855 end*} |
1858 end*} |
1856 |
1859 |
1857 text {* |
1860 text {* |
1858 Here the redex is given as a @{ML_type term}, instead of a @{ML_type cterm} |
1861 Here the redex is given as a @{ML_type term}, instead of a @{ML_type cterm} |
1859 (therefore we printing it out using the function @{ML pretty_term in Pretty}). |
1862 (therefore we printing it out using the function @{ML pretty_term in Pretty}). |
1860 We can turn this function into a proper simproc using the function |
1863 We can turn this function into a proper simproc using the function |
1861 @{ML Simplifier.simproc_global_i}: |
1864 @{ML Simplifier.make_simproc}: |
1862 *} |
1865 *} |
1863 |
1866 |
1864 |
1867 ML %grayML{*val fail' = |
1865 ML %grayML{*fun fail' ctxt = |
1868 Simplifier.make_simproc @{context} "fail_simproc'" |
1866 let |
1869 {lhss = [@{term "Suc n"}], proc = fail_simproc'}*} |
1867 val thy = @{theory} |
|
1868 val pat = [@{term "Suc n"}] |
|
1869 in |
|
1870 Simplifier.simproc_global_i thy "fail_simproc'" pat (K fail_simproc' ctxt) |
|
1871 end*} |
|
1872 |
1870 |
1873 text {* |
1871 text {* |
1874 Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}). |
1872 Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}). |
1875 The function also takes a list of patterns that can trigger the simproc. |
1873 The function also takes a list of patterns that can trigger the simproc. |
1876 Now the simproc is set up and can be explicitly added using |
1874 Now the simproc is set up and can be explicitly added using |
1908 the rewriting with simprocs, let us further assume we want that the simproc |
1906 the rewriting with simprocs, let us further assume we want that the simproc |
1909 only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write |
1907 only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write |
1910 *} |
1908 *} |
1911 |
1909 |
1912 |
1910 |
1913 ML %grayML{*fun plus_one_simproc ctxt redex = |
1911 ML %grayML{*fun plus_one_simproc _ ctxt redex = |
1914 case redex of |
1912 case Thm.term_of redex of |
1915 @{term "Suc 0"} => NONE |
1913 @{term "Suc 0"} => NONE |
1916 | _ => SOME @{thm plus_one}*} |
1914 | _ => SOME @{thm plus_one}*} |
1917 |
1915 |
1918 text {* |
1916 text {* |
1919 and set up the simproc as follows. |
1917 and set up the simproc as follows. |
1920 *} |
1918 *} |
1921 |
1919 |
1922 ML %grayML{*fun plus_one ctxt = |
1920 ML %grayML{*val plus_one = |
1923 let |
1921 Simplifier.make_simproc @{context} "sproc +1" |
1924 val thy = @{theory} |
1922 {lhss = [@{term "Suc n"}], proc = plus_one_simproc}*} |
1925 val pat = [@{term "Suc n"}] |
|
1926 in |
|
1927 Simplifier.simproc_global_i thy "sproc +1" pat (K plus_one_simproc ctxt) |
|
1928 end*} |
|
1929 |
1923 |
1930 text {* |
1924 text {* |
1931 Now the simproc is set up so that it is triggered by terms |
1925 Now the simproc is set up so that it is triggered by terms |
1932 of the form @{term "Suc n"}, but inside the simproc we only produce |
1926 of the form @{term "Suc n"}, but inside the simproc we only produce |
1933 a theorem if the term is not @{term "Suc 0"}. The result you can see |
1927 a theorem if the term is not @{term "Suc 0"}. The result you can see |
1934 in the following proof |
1928 in the following proof |
1935 *} |
1929 *} |
1936 |
1930 |
1937 lemma |
1931 lemma |
1938 shows "P (Suc (Suc (Suc 0))) (Suc 0)" |
1932 shows "P (Suc (Suc (Suc 0))) (Suc 0)" |
1939 apply(tactic {* simp_tac (put_simpset HOL_basic_ss @{context} addsimprocs [plus_one @{context}]) 1*}) |
1933 apply(tactic {* simp_tac (put_simpset HOL_basic_ss @{context} addsimprocs [plus_one]) 1*}) |
1940 txt{* |
1934 txt{* |
1941 where the simproc produces the goal state |
1935 where the simproc produces the goal state |
1942 \begin{isabelle} |
1936 \begin{isabelle} |
1943 @{subgoals[display]} |
1937 @{subgoals[display]} |
1944 \end{isabelle} |
1938 \end{isabelle} |
2009 |
2003 |
2010 Anyway, either version can be used in the function that produces the actual |
2004 Anyway, either version can be used in the function that produces the actual |
2011 theorem for the simproc. |
2005 theorem for the simproc. |
2012 *} |
2006 *} |
2013 |
2007 |
2014 ML %grayML{*fun nat_number_simproc ctxt t = |
2008 ML %grayML{*fun nat_number_simproc _ ctxt ct = |
2015 SOME (get_thm_alt ctxt (t, dest_suc_trm t)) |
2009 SOME (get_thm_alt ctxt (Thm.term_of ct, dest_suc_trm (Thm.term_of ct))) |
2016 handle TERM _ => NONE *} |
2010 handle TERM _ => NONE *} |
2017 |
2011 |
2018 text {* |
2012 text {* |
2019 This function uses the fact that @{ML dest_suc_trm} might raise an exception |
2013 This function uses the fact that @{ML dest_suc_trm} might raise an exception |
2020 @{ML TERM}. In this case there is nothing that can be rewritten and therefore no |
2014 @{ML TERM}. In this case there is nothing that can be rewritten and therefore no |
2021 theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc |
2015 theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc |
2022 on an example, you can set it up as follows: |
2016 on an example, you can set it up as follows: |
2023 *} |
2017 *} |
2024 |
2018 |
2025 ML %grayML{*fun nat_number ctxt = |
2019 ML %grayML{*val nat_number = |
2026 let |
2020 Simplifier.make_simproc @{context} "nat_number" |
2027 val thy = @{theory} |
2021 {lhss = [@{term "Suc n"}], proc = nat_number_simproc}*} |
2028 val pat = [@{term "Suc n"}] |
2022 |
2029 in |
|
2030 Simplifier.simproc_global_i thy "nat_number" pat (K nat_number_simproc ctxt) |
|
2031 end*} |
|
2032 |
2023 |
2033 text {* |
2024 text {* |
2034 Now in the lemma |
2025 Now in the lemma |
2035 *} |
2026 *} |
2036 |
2027 |
2037 lemma |
2028 lemma |
2038 shows "P (Suc (Suc 2)) (Suc 99) (0::nat) (Suc 4 + Suc 0) (Suc (0 + 0))" |
2029 shows "P (Suc (Suc 2)) (Suc 99) (0::nat) (Suc 4 + Suc 0) (Suc (0 + 0))" |
2039 apply(tactic {* simp_tac (put_simpset HOL_ss @{context} addsimprocs [nat_number @{context}]) 1*}) |
2030 apply(tactic {* simp_tac (put_simpset HOL_ss @{context} addsimprocs [nat_number]) 1*}) |
2040 txt {* |
2031 txt {* |
2041 you obtain the more legible goal state |
2032 you obtain the more legible goal state |
2042 \begin{isabelle} |
2033 \begin{isabelle} |
2043 @{subgoals [display]} |
2034 @{subgoals [display]} |
2044 \end{isabelle}*} |
2035 \end{isabelle}*} |
2489 @{ML_type "cterm -> thm"}). The code of the transformation is below. |
2480 @{ML_type "cterm -> thm"}). The code of the transformation is below. |
2490 *} |
2481 *} |
2491 |
2482 |
2492 ML %linenosgray{*fun unabs_def ctxt def = |
2483 ML %linenosgray{*fun unabs_def ctxt def = |
2493 let |
2484 let |
2494 val (lhs, rhs) = Thm.dest_equals (cprop_of def) |
2485 val (lhs, rhs) = Thm.dest_equals (Thm.cprop_of def) |
2495 val xs = strip_abs_vars (term_of rhs) |
2486 val xs = strip_abs_vars (Thm.term_of rhs) |
2496 val (_, ctxt') = Variable.add_fixes (map fst xs) ctxt |
2487 val (_, ctxt') = Variable.add_fixes (map fst xs) ctxt |
2497 |
2488 |
2498 val thy = Proof_Context.theory_of ctxt' |
2489 val cxs = map (Thm.cterm_of ctxt' o Free) xs |
2499 val cxs = map (cterm_of thy o Free) xs |
|
2500 val new_lhs = Drule.list_comb (lhs, cxs) |
2490 val new_lhs = Drule.list_comb (lhs, cxs) |
2501 |
2491 |
2502 fun get_conv [] = Conv.rewr_conv def |
2492 fun get_conv [] = Conv.rewr_conv def |
2503 | get_conv (_::xs) = Conv.fun_conv (get_conv xs) |
2493 | get_conv (_::xs) = Conv.fun_conv (get_conv xs) |
2504 in |
2494 in |