796 then you can use the combinator @{ML ORELSE'} for two tactics, and @{ML |
796 then you can use the combinator @{ML ORELSE'} for two tactics, and @{ML |
797 FIRST'} (or @{ML FIRST1}) for a list of tactics. For example, the tactic |
797 FIRST'} (or @{ML FIRST1}) for a list of tactics. For example, the tactic |
798 |
798 |
799 *} |
799 *} |
800 |
800 |
801 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
801 ML{*val orelse_xmp = rtac @{thm disjI1} ORELSE' rtac @{thm conjI}*} |
802 |
802 |
803 text {* |
803 text {* |
804 will first try out whether rule @{text disjI} applies and after that |
804 will first try out whether rule @{text disjI} applies and after that |
805 @{text conjI}. To see this consider the proof |
805 @{text conjI}. To see this consider the proof |
806 *} |
806 *} |
1057 simproc_setup fail_sp ("Suc n") = {* K fail_sp_aux *} |
1057 simproc_setup fail_sp ("Suc n") = {* K fail_sp_aux *} |
1058 |
1058 |
1059 text {* |
1059 text {* |
1060 where the second argument specifies the pattern and the right-hand side |
1060 where the second argument specifies the pattern and the right-hand side |
1061 contains the code of the simproc (we have to use @{ML K} since we ignoring |
1061 contains the code of the simproc (we have to use @{ML K} since we ignoring |
1062 an argument about a morphism\footnote{FIXME: what does the morphism do?}). |
1062 an argument about morphisms\footnote{FIXME: what does the morphism do?}). |
1063 After this, the simplifier is aware of the simproc and you can test whether |
1063 After this, the simplifier is aware of the simproc and you can test whether |
1064 it fires on the lemma |
1064 it fires on the lemma: |
1065 *} |
1065 *} |
1066 |
1066 |
1067 lemma shows "Suc 0 = 1" |
1067 lemma shows "Suc 0 = 1" |
1068 apply(simp) |
1068 apply(simp) |
1069 (*<*)oops(*>*) |
1069 (*<*)oops(*>*) |
1070 |
1070 |
1071 text {* |
1071 text {* |
1072 This will print out the message twice: once for the left-hand side and |
1072 This will print out the message twice: once for the left-hand side and |
1073 once for the right-hand side. The reason is that during simplification the |
1073 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 |
1074 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. |
1075 0"}, and then the simproc ``fires'' also on that term. |
1076 |
1076 |
1077 We can add or delete the simproc by the usual \isacommand{declare}-statement. |
1077 We can add or delete the simproc from the current simpset by the usual |
1078 For example the simproc will be deleted if you type: |
1078 \isacommand{declare}-statement. For example the simproc will be deleted |
|
1079 if you type: |
1079 *} |
1080 *} |
1080 |
1081 |
1081 declare [[simproc del: fail_sp]] |
1082 declare [[simproc del: fail_sp]] |
1082 |
1083 |
1083 text {* |
1084 text {* |
1085 interference from other rewrite rules, you can call @{text fail_sp} |
1086 interference from other rewrite rules, you can call @{text fail_sp} |
1086 as follows: |
1087 as follows: |
1087 *} |
1088 *} |
1088 |
1089 |
1089 lemma shows "Suc 0 = 1" |
1090 lemma shows "Suc 0 = 1" |
1090 apply(tactic {* simp_tac (HOL_ss addsimprocs [@{simproc fail_sp}]) 1*}) |
1091 apply(tactic {* simp_tac (HOL_ss addsimprocs [@{simproc fail_sp}]) 1*}) |
1091 (*<*)oops(*>*) |
1092 (*<*)oops(*>*) |
1092 |
1093 |
1093 text {* |
1094 text {* |
1094 (FIXME: should one use HOL-basic-ss or HOL-ss?) |
1095 (FIXME: should one use HOL-basic-ss or HOL-ss?) |
1095 |
1096 |
1096 Now the message shows up only once since @{term "1::nat"} is left unchanged. |
1097 Now the message shows up only once since the term @{term "1::nat"} is |
|
1098 left unchanged. |
1097 |
1099 |
1098 Setting up a simproc using the command \isacommand{setup\_simproc} will |
1100 Setting up a simproc using the command \isacommand{setup\_simproc} will |
1099 always add automatically the simproc to the current simpset. If you do not |
1101 always add automatically the simproc to the current simpset. If you do not |
1100 want this, then you have to use a slightly different method for setting |
1102 want this, then you have to use a slightly different method for setting |
1101 up the simproc. First the function @{ML fail_sp_aux} needs to be modified |
1103 up the simproc. First the function @{ML fail_sp_aux} needs to be modified |
1131 It might be interesting to notice that simprocs are applied from inside |
1133 It might be interesting to notice that simprocs are applied from inside |
1132 to outside and from left to right. You can see this in the proof |
1134 to outside and from left to right. You can see this in the proof |
1133 *} |
1135 *} |
1134 |
1136 |
1135 lemma shows "Suc (Suc 0) = (Suc 1)" |
1137 lemma shows "Suc (Suc 0) = (Suc 1)" |
1136 apply(tactic {* simp_tac (HOL_ss addsimprocs [fail_sp']) 1*}) |
1138 apply(tactic {* simp_tac (HOL_ss addsimprocs [fail_sp']) 1*}) |
1137 (*<*)oops(*>*) |
1139 (*<*)oops(*>*) |
1138 |
1140 |
1139 text {* |
1141 text {* |
1140 since the @{ML fail_sp'}-simproc prints out the sequence |
1142 since @{ML fail_sp'} prints out the sequence |
1141 |
1143 |
1142 @{text [display] |
1144 @{text [display] |
1143 "> Suc 0 |
1145 "> Suc 0 |
1144 > Suc (Suc 0) |
1146 > Suc (Suc 0) |
1145 > Suc 1"} |
1147 > Suc 1"} |
1146 |
1148 |
1147 To see how a simproc applies a theorem let us implement a simproc that |
1149 To see how a simproc applies a theorem, let us implement a simproc that |
1148 rewrites terms according to the equation: |
1150 rewrites terms according to the equation: |
1149 *} |
1151 *} |
1150 |
1152 |
1151 lemma plus_one: |
1153 lemma plus_one: |
1152 shows "Suc n \<equiv> n + 1" by simp |
1154 shows "Suc n \<equiv> n + 1" by simp |
1153 |
1155 |
1154 text {* |
1156 text {* |
1155 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 |
1156 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 |
1157 preconditions can be solved). To see how rewriting can be tuned precisely, let us |
1159 preconditions can be solved). To see one has relatively precise control over |
1158 further assume we want that the simproc only rewrites terms greater than |
1160 the rewriting with simprocs, let us further assume we want that the simproc |
1159 @{term "Suc 0"}. For this we can write |
1161 only rewrites terms ``greater'' than @{term "Suc 0"}. For this we can write |
1160 *} |
1162 *} |
|
1163 |
1161 |
1164 |
1162 ML{*fun plus_one_sp_aux ss redex = |
1165 ML{*fun plus_one_sp_aux ss redex = |
1163 case redex of |
1166 case redex of |
1164 @{term "Suc 0"} => NONE |
1167 @{term "Suc 0"} => NONE |
1165 | _ => SOME @{thm plus_one}*} |
1168 | _ => SOME @{thm plus_one}*} |
1175 in |
1178 in |
1176 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) |
1177 end*} |
1180 end*} |
1178 |
1181 |
1179 text {* |
1182 text {* |
1180 Now the have set up the simproc so that it is triggered by terms |
1183 Now the simproc is set up xso that it is triggered by terms |
1181 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 |
1182 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 |
1183 in the following proof. |
1186 in the following proof |
1184 *} |
1187 *} |
1185 |
1188 |
1186 lemma shows "P (Suc (Suc (Suc 0))) (Suc 0)" |
1189 lemma shows "P (Suc (Suc (Suc 0))) (Suc 0)" |
1187 apply(tactic {* simp_tac (HOL_ss addsimprocs [plus_one_sp]) 1*}) |
1190 apply(tactic {* simp_tac (HOL_ss addsimprocs [plus_one_sp]) 1*}) |
1188 txt{* |
1191 txt{* |
1189 the simproc produces the goal state |
1192 where the simproc produces the goal state |
1190 |
1193 |
1191 @{subgoals[display]} |
1194 @{subgoals[display]} |
1192 *} |
1195 *} |
1193 (*<*)oops(*>*) |
1196 (*<*)oops(*>*) |
1194 |
1197 |
1195 text {* |
1198 text {* |
1196 As usual with simplification you have to be careful with loops: you already have |
1199 As usual with simplification you have to be careful with looping: you already have |
1197 one @{ML plus_one_sp}, if you apply if with the default simpset (because |
1200 one @{ML plus_one_sp}, if you apply if with the default simpset (because |
1198 the default simpset contains a rule which just undoes the rewriting |
1201 the default simpset contains a rule which just undoes the rewriting |
1199 @{ML plus_one_sp}). |
1202 @{ML plus_one_sp}). |
1200 |
1203 |
1201 Let us next implement a simproc that replaces terms of the form @{term "Suc n"} |
1204 Let us next implement a simproc that replaces terms of the form @{term "Suc n"} |
1208 | dest_suc_trm t = snd (HOLogic.dest_number t)*} |
1211 | dest_suc_trm t = snd (HOLogic.dest_number t)*} |
1209 |
1212 |
1210 text {* |
1213 text {* |
1211 It uses the library function @{ML dest_number in HOLogic} that transforms |
1214 It uses the library function @{ML dest_number in HOLogic} that transforms |
1212 (Isabelle) terms, like @{term "0::nat"}, @{term "1::nat"}, @{term "2::nat"} and so |
1215 (Isabelle) terms, like @{term "0::nat"}, @{term "1::nat"}, @{term "2::nat"} and so |
1213 on, into integer values. This function raises the exception @{ML TERM} if |
1216 on, into integer values. This function raises the exception @{ML TERM}, if |
1214 the term is not a number. The next function expects a pair consisting of a term |
1217 the term is not a number. The next function expects a pair consisting of a term |
1215 @{text t} and the corresponding integer value @{text n}. |
1218 @{text t} (containing @{term Suc}s) and the corresponding integer value @{text n}. |
1216 *} |
1219 *} |
1217 |
1220 |
1218 ML %linenosgray{*fun get_thm ctxt (t, n) = |
1221 ML %linenosgray{*fun get_thm ctxt (t, n) = |
1219 let |
1222 let |
1220 val num = HOLogic.mk_number @{typ "nat"} n |
1223 val num = HOLogic.mk_number @{typ "nat"} n |
1222 in |
1225 in |
1223 mk_meta_eq (Goal.prove ctxt [] [] goal (K (simp_tac @{simpset} 1))) |
1226 mk_meta_eq (Goal.prove ctxt [] [] goal (K (simp_tac @{simpset} 1))) |
1224 end*} |
1227 end*} |
1225 |
1228 |
1226 text {* |
1229 text {* |
1227 From the integer value it generates the corresponding Isabelle term, called |
1230 (FIXME: is @{text "@{simpset}"} kosher here? Otherwise the following will loop.) |
1228 @{text num} (Line 3), and then generates the equation @{text "t = num"} (Line 4) |
1231 |
|
1232 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), |
1229 which it proves by simplification in Line 6. The function @{ML mk_meta_eq} |
1234 which it proves by simplification in Line 6. The function @{ML mk_meta_eq} |
1230 at the outside of the proof just transforms the equality to a meta-equality. |
1235 at the outside of the proof just transforms the equality into a meta-equality. |
1231 |
1236 |
1232 Both functions can be stringed together in the function that produces the |
1237 Both functions can be stringed together in the function that produces the |
1233 actual theorem for the simproc. |
1238 actual theorem for the simproc. |
1234 *} |
1239 *} |
1235 |
1240 |
1240 SOME (get_thm ctxt (t, dest_suc_trm t)) |
1245 SOME (get_thm ctxt (t, dest_suc_trm t)) |
1241 handle TERM _ => NONE |
1246 handle TERM _ => NONE |
1242 end*} |
1247 end*} |
1243 |
1248 |
1244 text {* |
1249 text {* |
1245 (FIXME: is @{text "@{simpset}"} kosher here? Otherwise the following will loop.) |
|
1246 |
|
1247 This function uses the fact that @{ML dest_suc_trm} might throw an exception |
1250 This function uses the fact that @{ML dest_suc_trm} might throw an exception |
1248 @{ML TERM}. In this case there is nothing that can be rewritten and therefore no |
1251 @{ML TERM}. In this case there is nothing that can be rewritten and therefore no |
1249 theorem is produced. To try out the simproc on an example, you can set it up as |
1252 theorem is produced (i.e.~the function returns @{ML NONE}). To try out the simproc |
1250 follows: |
1253 on an example, you can set it up as follows: |
1251 *} |
1254 *} |
1252 |
1255 |
1253 ML{*val nat_number_sp = |
1256 ML{*val nat_number_sp = |
1254 let |
1257 let |
1255 val thy = @{theory} |
1258 val thy = @{theory} |