CookBook/Tactical.thy
changeset 132 2d9198bcb850
parent 131 8db9195bb3e9
child 133 3e94ccc0f31e
equal deleted inserted replaced
131:8db9195bb3e9 132:2d9198bcb850
    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! 
   208   let us modify the code of @{ML all_tac} to obtain the following
   206   let us modify the code of @{ML all_tac} to obtain the following
   209   tactic
   207   tactic
   210 *}
   208 *}
   211 
   209 
   212 ML{*fun my_print_tac ctxt thm =
   210 ML{*fun my_print_tac ctxt thm =
   213  let
   211 let
   214    val _ = warning (str_of_thm ctxt thm)
   212   val _ = warning (str_of_thm ctxt thm)
   215  in 
   213 in 
   216    Seq.single thm
   214   Seq.single thm
   217  end*}
   215 end*}
   218 
   216 
   219 text_raw {*
   217 text_raw {*
   220   \begin{figure}[p]
   218   \begin{figure}[p]
   221   \begin{isabelle}
   219   \begin{isabelle}
   222 *}
   220 *}
   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
  1252   theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc 
  1277   theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc 
  1253   on an example, you can set it up as follows:
  1278   on an example, you can set it up as follows:
  1254 *}
  1279 *}
  1255 
  1280 
  1256 ML{*val nat_number_sp =
  1281 ML{*val nat_number_sp =
  1257   let
  1282 let
  1258     val thy = @{theory}
  1283   val thy = @{theory}
  1259     val pat = [@{term "Suc n"}]
  1284   val pat = [@{term "Suc n"}]
  1260   in 
  1285 in 
  1261     Simplifier.simproc_i thy "nat_number" pat (K nat_number_sp_aux) 
  1286   Simplifier.simproc_i thy "nat_number" pat (K nat_number_sp_aux) 
  1262   end*}
  1287 end*}
  1263 
  1288 
  1264 text {* 
  1289 text {* 
  1265   Now in the lemma
  1290   Now in the lemma
  1266   *}
  1291   *}
  1267 
  1292 
  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 
  1286   \end{exercise}
  1311   \end{exercise}
  1287 
  1312 
  1288   (FIXME: We did not do anything with morphisms. Anything interesting
  1313   (FIXME: We did not do anything with morphisms. Anything interesting
  1289   one can say about them?)
  1314   one can say about them?)
  1290 *}
  1315 *}
       
  1316 
       
  1317 section {* Conversions *}
       
  1318 
  1291 
  1319 
  1292 section {* Structured Proofs *}
  1320 section {* Structured Proofs *}
  1293 
  1321 
  1294 text {* TBD *}
  1322 text {* TBD *}
  1295 
  1323