66 "Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic |
66 "Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic |
67 tactics and tactic combinators; see also Chapters 3 and 4 in the old |
67 tactics and tactic combinators; see also Chapters 3 and 4 in the old |
68 Isabelle Reference Manual. |
68 Isabelle Reference Manual. |
69 \end{readmore} |
69 \end{readmore} |
70 |
70 |
71 (FIXME: what is @{ML Goal.prove_global}?) |
|
72 |
|
73 Note that in the code above we use antiquotations for referencing the theorems. Many theorems |
71 Note that in the code above we use antiquotations for referencing the theorems. Many theorems |
74 also have ML-bindings with the same name. Therefore, we could also just have |
72 also have ML-bindings with the same name. Therefore, we could also just have |
75 written @{ML "etac disjE 1"}, or in case where there are no ML-binding obtain |
73 written @{ML "etac disjE 1"}, or in case where there are no ML-binding obtain |
76 the theorem dynamically using the function @{ML thm}; for example |
74 the theorem dynamically using the function @{ML thm}; for example |
77 \mbox{@{ML "etac (thm \"disjE\") 1"}}. Both ways however are considered bad style! |
75 \mbox{@{ML "etac (thm \"disjE\") 1"}}. Both ways however are considered bad style! |
535 text_raw{* |
533 text_raw{* |
536 \begin{figure} |
534 \begin{figure} |
537 \begin{isabelle} |
535 \begin{isabelle} |
538 *} |
536 *} |
539 ML{*fun sp_tac {prems, params, asms, concl, context, schematics} = |
537 ML{*fun sp_tac {prems, params, asms, concl, context, schematics} = |
540 let |
538 let |
541 val str_of_params = str_of_cterms context params |
539 val str_of_params = str_of_cterms context params |
542 val str_of_asms = str_of_cterms context asms |
540 val str_of_asms = str_of_cterms context asms |
543 val str_of_concl = str_of_cterm context concl |
541 val str_of_concl = str_of_cterm context concl |
544 val str_of_prems = str_of_thms context prems |
542 val str_of_prems = str_of_thms context prems |
545 val str_of_schms = str_of_cterms context (snd schematics) |
543 val str_of_schms = str_of_cterms context (snd schematics) |
546 |
544 |
547 val _ = (warning ("params: " ^ str_of_params); |
545 val _ = (warning ("params: " ^ str_of_params); |
548 warning ("schematics: " ^ str_of_schms); |
546 warning ("schematics: " ^ str_of_schms); |
549 warning ("assumptions: " ^ str_of_asms); |
547 warning ("assumptions: " ^ str_of_asms); |
550 warning ("conclusion: " ^ str_of_concl); |
548 warning ("conclusion: " ^ str_of_concl); |
551 warning ("premises: " ^ str_of_prems)) |
549 warning ("premises: " ^ str_of_prems)) |
552 in |
550 in |
553 no_tac |
551 no_tac |
554 end*} |
552 end*} |
555 text_raw{* |
553 text_raw{* |
556 \end{isabelle} |
554 \end{isabelle} |
557 \caption{A function that prints out the various parameters provided by the tactic |
555 \caption{A function that prints out the various parameters provided by the tactic |
558 @{ML SUBPROOF}. It uses the functions defined in Section~\ref{sec:printing} for |
556 @{ML SUBPROOF}. It uses the functions defined in Section~\ref{sec:printing} for |
559 extracting strings from @{ML_type cterm}s and @{ML_type thm}s.\label{fig:sptac}} |
557 extracting strings from @{ML_type cterm}s and @{ML_type thm}s.\label{fig:sptac}} |
1030 rewrite a term according to theorem. They are useful in cases where |
1028 rewrite a term according to theorem. They are useful in cases where |
1031 a rewriting rule must be produced on ``demand'' or when rewriting by |
1029 a rewriting rule must be produced on ``demand'' or when rewriting by |
1032 simplification is too unpredictable and potentially loops. |
1030 simplification is too unpredictable and potentially loops. |
1033 |
1031 |
1034 To see how simprocs work, let us first write a simproc that just prints out |
1032 To see how simprocs work, let us first write a simproc that just prints out |
1035 the pattern that triggers it and otherwise does nothing. For this |
1033 the pattern which triggers it and otherwise does nothing. For this |
1036 you can use the function: |
1034 you can use the function: |
1037 *} |
1035 *} |
1038 |
1036 |
1039 ML %linenosgray{*fun fail_sp_aux simpset redex = |
1037 ML %linenosgray{*fun fail_sp_aux simpset redex = |
1040 let |
1038 let |
1044 NONE |
1042 NONE |
1045 end*} |
1043 end*} |
1046 |
1044 |
1047 text {* |
1045 text {* |
1048 This function takes a simpset and a redex (a @{ML_type cterm}) as |
1046 This function takes a simpset and a redex (a @{ML_type cterm}) as |
1049 argument. In Lines 3 and~4, we first extract the context from the given |
1047 arguments. In Lines 3 and~4, we first extract the context from the given |
1050 simpset and then print out a message containing the redex. The function |
1048 simpset and then print out a message containing the redex. The function |
1051 returns @{ML NONE} (standing for an optional @{ML_type thm}) since at the |
1049 returns @{ML NONE} (standing for an optional @{ML_type thm}) since at the |
1052 moment we are \emph{not} interested in actually rewriting anything. We want |
1050 moment we are \emph{not} interested in actually rewriting anything. We want |
1053 that the simproc is triggered by the pattern @{term "Suc n"}. This can be |
1051 that the simproc is triggered by the pattern @{term "Suc n"}. This can be |
1054 done by adding the simproc to the current simproc as follows |
1052 done by adding the simproc to the current simproc as follows |
1073 once for the right-hand side. The reason is that during simplification the |
1071 once for the right-hand side. The reason is that during simplification the |
1074 simplifier will at some point reduce the term @{term "1::nat"} to @{term "Suc |
1072 simplifier will at some point reduce the term @{term "1::nat"} to @{term "Suc |
1075 0"}, and then the simproc ``fires'' also on that term. |
1073 0"}, and then the simproc ``fires'' also on that term. |
1076 |
1074 |
1077 We can add or delete the simproc from the current simpset by the usual |
1075 We can add or delete the simproc from the current simpset by the usual |
1078 \isacommand{declare}-statement. For example the simproc will be deleted |
1076 \isacommand{declare}-statement. For example the simproc will be deleted |
1079 if you type: |
1077 with the declaration |
1080 *} |
1078 *} |
1081 |
1079 |
1082 declare [[simproc del: fail_sp]] |
1080 declare [[simproc del: fail_sp]] |
1083 |
1081 |
1084 text {* |
1082 text {* |
1086 interference from other rewrite rules, you can call @{text fail_sp} |
1084 interference from other rewrite rules, you can call @{text fail_sp} |
1087 as follows: |
1085 as follows: |
1088 *} |
1086 *} |
1089 |
1087 |
1090 lemma shows "Suc 0 = 1" |
1088 lemma shows "Suc 0 = 1" |
1091 apply(tactic {* simp_tac (HOL_ss addsimprocs [@{simproc fail_sp}]) 1*}) |
1089 apply(tactic {* simp_tac (HOL_basic_ss addsimprocs [@{simproc fail_sp}]) 1*}) |
1092 (*<*)oops(*>*) |
1090 (*<*)oops(*>*) |
1093 |
1091 |
1094 text {* |
1092 text {* |
1095 (FIXME: should one use HOL-basic-ss or HOL-ss?) |
|
1096 |
|
1097 Now the message shows up only once since the term @{term "1::nat"} is |
1093 Now the message shows up only once since the term @{term "1::nat"} is |
1098 left unchanged. |
1094 left unchanged. |
1099 |
1095 |
1100 Setting up a simproc using the command \isacommand{setup\_simproc} will |
1096 Setting up a simproc using the command \isacommand{setup\_simproc} will |
1101 always add automatically the simproc to the current simpset. If you do not |
1097 always add automatically the simproc to the current simpset. If you do not |
1128 end*} |
1124 end*} |
1129 |
1125 |
1130 text {* |
1126 text {* |
1131 Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}). |
1127 Here the pattern is given as @{ML_type term} (instead of @{ML_type cterm}). |
1132 The function also takes a list of patterns that can trigger the simproc. |
1128 The function also takes a list of patterns that can trigger the simproc. |
1133 It might be interesting to notice that simprocs are applied from inside |
1129 Now the simproc is set up and can be explicitly added using |
1134 to outside and from left to right. You can see this in the proof |
1130 {ML addsimprocs} to a simpset whenerver |
|
1131 needed. |
|
1132 |
|
1133 Simprocs are applied from inside to outside and from left to right. You can |
|
1134 see this in the proof |
1135 *} |
1135 *} |
1136 |
1136 |
1137 lemma shows "Suc (Suc 0) = (Suc 1)" |
1137 lemma shows "Suc (Suc 0) = (Suc 1)" |
1138 apply(tactic {* simp_tac (HOL_ss addsimprocs [fail_sp']) 1*}) |
1138 apply(tactic {* simp_tac (HOL_ss addsimprocs [fail_sp']) 1*}) |
1139 (*<*)oops(*>*) |
1139 (*<*)oops(*>*) |
1140 |
1140 |
1141 text {* |
1141 text {* |
1142 since @{ML fail_sp'} prints out the sequence |
1142 The simproc @{ML fail_sp'} prints out the sequence |
1143 |
1143 |
1144 @{text [display] |
1144 @{text [display] |
1145 "> Suc 0 |
1145 "> Suc 0 |
1146 > Suc (Suc 0) |
1146 > Suc (Suc 0) |
1147 > Suc 1"} |
1147 > Suc 1"} |
1154 shows "Suc n \<equiv> n + 1" by simp |
1154 shows "Suc n \<equiv> n + 1" by simp |
1155 |
1155 |
1156 text {* |
1156 text {* |
1157 Simprocs expect that the given equation is a meta-equation, however the |
1157 Simprocs expect that the given equation is a meta-equation, however the |
1158 equation can contain preconditions (the simproc then will only fire if the |
1158 equation can contain preconditions (the simproc then will only fire if the |
1159 preconditions can be solved). To see one has relatively precise control over |
1159 preconditions can be solved). To see that one has relatively precise control over |
1160 the rewriting with simprocs, let us further assume we want that the simproc |
1160 the rewriting with simprocs, let us further assume we want that the simproc |
1161 only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write |
1161 only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write |
1162 *} |
1162 *} |
1163 |
1163 |
1164 |
1164 |
1178 in |
1178 in |
1179 Simplifier.simproc_i thy "sproc +1" pat (K plus_one_sp_aux) |
1179 Simplifier.simproc_i thy "sproc +1" pat (K plus_one_sp_aux) |
1180 end*} |
1180 end*} |
1181 |
1181 |
1182 text {* |
1182 text {* |
1183 Now the simproc is set up xso that it is triggered by terms |
1183 Now the simproc is set up so that it is triggered by terms |
1184 of the form @{term "Suc n"}, but inside the simproc we only produce |
1184 of the form @{term "Suc n"}, but inside the simproc we only produce |
1185 a theorem if the term is not @{term "Suc 0"}. The result you can see |
1185 a theorem if the term is not @{term "Suc 0"}. The result you can see |
1186 in the following proof |
1186 in the following proof |
1187 *} |
1187 *} |
1188 |
1188 |
1194 @{subgoals[display]} |
1194 @{subgoals[display]} |
1195 *} |
1195 *} |
1196 (*<*)oops(*>*) |
1196 (*<*)oops(*>*) |
1197 |
1197 |
1198 text {* |
1198 text {* |
1199 As usual with simplification you have to be careful with looping: you already have |
1199 As usual with simplification you have to worry about looping: you already have |
1200 one @{ML plus_one_sp}, if you apply if with the default simpset (because |
1200 a loop with @{ML plus_one_sp}, if you apply it with the default simpset (because |
1201 the default simpset contains a rule which just undoes the rewriting |
1201 the default simpset contains a rule which just does the opposite of @{ML plus_one_sp}, |
1202 @{ML plus_one_sp}). |
1202 namely rewriting @{text [quotes] "+ 1"} to a successor). So you have to be careful |
1203 |
1203 in choosing the right simpset to which you add a simproc. |
1204 Let us next implement a simproc that replaces terms of the form @{term "Suc n"} |
1204 |
|
1205 Next let us implement a simproc that replaces terms of the form @{term "Suc n"} |
1205 with the number @{text n} increase by one. First we implement a function that |
1206 with the number @{text n} increase by one. First we implement a function that |
1206 takes a term and produces the corresponding integer value, if it can. |
1207 takes a term and produces the corresponding integer value. |
1207 |
1208 |
1208 *} |
1209 *} |
1209 |
1210 |
1210 ML{*fun dest_suc_trm ((Const (@{const_name "Suc"}, _)) $ t) = 1 + dest_suc_trm t |
1211 ML{*fun dest_suc_trm ((Const (@{const_name "Suc"}, _)) $ t) = 1 + dest_suc_trm t |
1211 | dest_suc_trm t = snd (HOLogic.dest_number t)*} |
1212 | dest_suc_trm t = snd (HOLogic.dest_number t)*} |
1219 *} |
1220 *} |
1220 |
1221 |
1221 ML %linenosgray{*fun get_thm ctxt (t, n) = |
1222 ML %linenosgray{*fun get_thm ctxt (t, n) = |
1222 let |
1223 let |
1223 val num = HOLogic.mk_number @{typ "nat"} n |
1224 val num = HOLogic.mk_number @{typ "nat"} n |
1224 val goal = HOLogic.mk_Trueprop (HOLogic.mk_eq (t,num)) |
1225 val goal = Logic.mk_equals (t, num) |
1225 in |
1226 in |
1226 mk_meta_eq (Goal.prove ctxt [] [] goal (K (simp_tac @{simpset} 1))) |
1227 Goal.prove ctxt [] [] goal (K (arith_tac ctxt 1)) |
1227 end*} |
1228 end*} |
1228 |
1229 |
1229 text {* |
1230 text {* |
1230 (FIXME: is @{text "@{simpset}"} kosher here? Otherwise the following will loop.) |
|
1231 |
|
1232 From the integer value it generates the corresponding number term, called |
1231 From the integer value it generates the corresponding number term, called |
1233 @{text num} (Line 3), and then generates the equation @{text "t = num"} (Line 4), |
1232 @{text num} (Line 3), and then generates the meta-equation @{text "t \<equiv> num"} |
1234 which it proves by simplification in Line 6. The function @{ML mk_meta_eq} |
1233 (Line 4), which it proves by the arithmetic tactic in Line 6. |
1235 at the outside of the proof just transforms the equality into a meta-equality. |
1234 |
1236 |
1235 For our purpose at the moment, using in the code above @{ML arith_tac} is |
1237 Both functions can be stringed together in the function that produces the |
1236 fine, but there is also an alternative employing the simplifier with a very |
1238 actual theorem for the simproc. |
1237 restricted simpset. For the kind of lemmas we want to prove, the simpset |
|
1238 @{text "num_ss"} in the code will suffice. |
|
1239 *} |
|
1240 |
|
1241 ML{*fun get_thm_alt ctxt (t, n) = |
|
1242 let |
|
1243 val num = HOLogic.mk_number @{typ "nat"} n |
|
1244 val goal = Logic.mk_equals (t, num) |
|
1245 val num_ss = HOL_ss addsimps [@{thm One_nat_def}, @{thm Let_def}] @ |
|
1246 @{thms nat_number} @ @{thms neg_simps} @ @{thms plus_nat.simps} |
|
1247 in |
|
1248 Goal.prove ctxt [] [] goal (K (simp_tac num_ss 1)) |
|
1249 end*} |
|
1250 |
|
1251 text {* |
|
1252 The advantage of @{ML get_thm_alt} is that it leaves very little room for |
|
1253 something to go wrong; in contrast it is much more difficult to predict |
|
1254 what happens with @{ML arith_tac}, especially in more complicated |
|
1255 circumstances. The disatvantage of @{ML get_thm_alt} is to find a simpset |
|
1256 that is sufficiently powerful to solve every instance of the lemmas |
|
1257 we like to prove. This requires careful tuning, but is often necessary in |
|
1258 ``production code''.\footnote{It would be of great help if there is another |
|
1259 way than tracing the simplifier to obtain the lemmas that are successfully |
|
1260 applied during simplification. Alas, there is none.} |
|
1261 |
|
1262 Anyway, either version can be used in the function that produces the actual |
|
1263 theorem for the simproc. |
1239 *} |
1264 *} |
1240 |
1265 |
1241 ML{*fun nat_number_sp_aux ss t = |
1266 ML{*fun nat_number_sp_aux ss t = |
1242 let |
1267 let |
1243 val ctxt = Simplifier.the_context ss |
1268 val ctxt = Simplifier.the_context ss |
1273 @{subgoals [display]} |
1298 @{subgoals [display]} |
1274 *} |
1299 *} |
1275 (*<*)oops(*>*) |
1300 (*<*)oops(*>*) |
1276 |
1301 |
1277 text {* |
1302 text {* |
1278 where the simproc rewrites all @{term "Suc"}s except in the last arguments. There it cannot |
1303 where the simproc rewrites all @{term "Suc"}s except in the last argument. There it cannot |
1279 rewrite anything, because it does not know how to transform the term @{term "Suc (0 + 0)"} |
1304 rewrite anything, because it does not know how to transform the term @{term "Suc (0 + 0)"} |
1280 into a number. To solve this problem have a look at the next exercise. |
1305 into a number. To solve this problem have a look at the next exercise. |
1281 |
1306 |
1282 \begin{exercise}\label{ex:addsimproc} |
1307 \begin{exercise}\label{ex:addsimproc} |
1283 Write a simproc that replaces terms of the form @{term "t\<^isub>1 + t\<^isub>2"} by their |
1308 Write a simproc that replaces terms of the form @{term "t\<^isub>1 + t\<^isub>2"} by their |