CookBook/Tactical.thy
changeset 139 ed1eb9cb2533
parent 135 8c31b729a5df
child 141 5aa3140ad52e
equal deleted inserted replaced
135:8c31b729a5df 139:ed1eb9cb2533
  1315 *}
  1315 *}
  1316 
  1316 
  1317 section {* Conversions *}
  1317 section {* Conversions *}
  1318 
  1318 
  1319 text {*
  1319 text {*
  1320 conversions: core of the simplifier
  1320 Conversions are meta-equalities depending on some input term. There type is
  1321 
  1321 as follows:
  1322 see: Pure/conv.ML
  1322 *}
  1323 *}
  1323 
  1324 
  1324 ML {*type conv = Thm.cterm -> Thm.thm*}
  1325 ML {* type conv = Thm.cterm -> Thm.thm *}
  1325 
  1326 
  1326 text {*
  1327 text {*
  1327 The simplest two conversions are @{ML "Conv.all_conv"} and @{ML "Conv.no_conv"}:
  1328 simple example:
  1328 
  1329 *}
  1329 @{ML_response_fake "Conv.all_conv @{cterm True}" "True \<equiv> True"}
  1330 
  1330 
  1331 lemma true_conj_1: "True \<and> P \<equiv> P" by simp
  1331 @{ML_response_fake "Conv.no_conv @{cterm True}" "*** Exception- CTERM (\"no conversion\", []) raised"}
  1332 
  1332 
  1333 ML {*
  1333 Further basic conversions are, for example, @{ML "Thm.beta_conversion"} and
  1334 val true1_conv = Conv.rewr_conv @{thm true_conj_1}
  1334  @{ML "Conv.rewr_conv"}:
  1335 *}
  1335 *}
  1336 
  1336 
  1337 ML {*
  1337 lemma true_conj1: "True \<and> P \<equiv> P" by simp
  1338 true1_conv @{cterm "True \<and> False"}
  1338 
  1339 *}
  1339 text {*
  1340 
  1340 @{ML_response_fake "Thm.beta_conversion true @{cterm \"(\<lambda>x. x \<or> False) True\"}"
  1341 text {*
  1341 "(\<lambda>x. x \<or> False) True \<equiv> True \<or> False"}
  1342 @{ML_response_fake "true1_conv @{cterm \"True \<and> False\"}"
  1342 
  1343   "True \<and> False \<equiv> False"}
  1343 @{ML_response_fake "Conv.rewr_conv @{thm true_conj1} @{cterm \"True \<or> False\"}"
  1344 *}
  1344  "True \<and> False \<equiv> False"}
  1345 
  1345 
  1346 text {*
  1346 Basic conversions can be combined with a number of conversionals, i.e.
  1347 how to extend rewriting to more complex cases? e.g.:
  1347 conversion combinators:
  1348 *}
  1348 
  1349 
  1349 @{ML_response_fake "Conv.then_conv (Thm.beta_conversion true, Conv.rewr_conv @{thm true_conj1}) @{cterm \"(\<lambda>x. x \<and> False) True\"}" "(\<lambda>x. x \<and> False) True \<equiv> False"}
  1350 ML {*
  1350 
  1351 val complex = @{cterm "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> (x::int)"}
  1351 @{ML_response_fake "Conv.else_conv (Conv.rewr_conv @{thm true_conj1}, Conv.all_conv) @{cterm \"P \<or> (True \<and> Q)\"}" "P \<or> (True \<and> Q) \<equiv> P \<or> (True \<and> Q)"}
  1352 *}
  1352 
  1353 
  1353 @{ML_response_fake "Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) @{cterm \"P \<or> (True \<and> Q)\"}" "P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
  1354 text {* conversionals: basically a count-down version of MetaSimplifier.rewrite *}
  1354 
  1355 
  1355 \begin{readmore}
  1356 ML {*
  1356 See @{ML_file "Pure/conv.ML"} for more conversionals. Further basic conversions
  1357 fun all_true1_conv ctxt ct =
  1357 can be found in, for example, @{ML_file "Pure/thm.ML"},
       
  1358 @{ML_file "Pure/drule.ML"}, and @{ML_file "Pure/meta_simplifier.ML"}.
       
  1359 \end{readmore}
       
  1360 
       
  1361 Conversions are a thin layer on top of Isabelle's inference kernel, and may
       
  1362 be seen as a controllable, bare-bone version of Isabelle's simplifier. We
       
  1363 will demonstrate this feature in the following example.
       
  1364 
       
  1365 For the moment, let's assumes we want to simplify according to the rewrite rule
       
  1366 @{thm true_conj1}. As a conversion, this may look as follows:
       
  1367 *}
       
  1368 
       
  1369 ML {*fun all_true1_conv ctxt ct =
  1358   (case Thm.term_of ct of
  1370   (case Thm.term_of ct of
  1359     @{term "op \<and>"} $ @{term True} $ _ => true1_conv ct
  1371     @{term "op \<and>"} $ @{term True} $ _ => Conv.rewr_conv @{thm true_conj1} ct
  1360   | _ $ _ => Conv.combination_conv (all_true1_conv ctxt) (all_true1_conv ctxt) ct
  1372   | _ $ _ => Conv.combination_conv (all_true1_conv ctxt) (all_true1_conv ctxt) ct
  1361   | Abs _ => Conv.abs_conv (fn (_, cx) => all_true1_conv cx) ctxt ct)
  1373   | Abs _ => Conv.abs_conv (fn (_, cx) => all_true1_conv cx) ctxt ct
  1362 *}
  1374   | _ => Conv.all_conv ct)*}
  1363 
  1375 
  1364 text {*
  1376 text {*
  1365 @{ML_response_fake "all_true1_conv @{context} complex"
  1377 Here is the new conversion in action:
       
  1378 
       
  1379 @{ML_response_fake "all_true1_conv @{context} @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}"
  1366   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
  1380   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
  1367 *}
  1381 
  1368 
  1382 Now, let's complicate the task: Rewrite according to the rule
  1369 
  1383 @{thm true_conj1}, but only in the first arguments of @{term If}:
  1370 text {*
  1384 *}
  1371 transforming theorems: @{ML "Conv.fconv_rule"} (give type)
  1385 
  1372 
  1386 ML {*fun if_true1_conv ctxt ct =
  1373 example:
       
  1374 *}
       
  1375 
       
  1376 lemma foo: "True \<and> (P \<or> \<not>P)" by simp
       
  1377 
       
  1378 text {*
       
  1379 @{ML_response_fake "Conv.fconv_rule (Conv.arg_conv (all_true1_conv @{context})) @{thm foo}" "P \<or> \<not>P"}
       
  1380 *}
       
  1381 
       
  1382 text {* now, replace "True and P" with "P" if it occurs inside an If *}
       
  1383 
       
  1384 ML {*
       
  1385 fun if_true1_conv ctxt ct =
       
  1386   (case Thm.term_of ct of
  1387   (case Thm.term_of ct of
  1387     Const (@{const_name If}, _) $ _ => Conv.arg_conv (all_true1_conv ctxt) ct
  1388     Const (@{const_name If}, _) $ _ => Conv.arg_conv (all_true1_conv ctxt) ct
  1388   | _ $ _ => Conv.combination_conv (if_true1_conv ctxt) (if_true1_conv ctxt) ct
  1389   | _ $ _ => Conv.combination_conv (if_true1_conv ctxt) (if_true1_conv ctxt) ct
  1389   | Abs _ => Conv.abs_conv (fn (_, cx) => if_true1_conv cx) ctxt ct)
  1390   | Abs _ => Conv.abs_conv (fn (_, cx) => if_true1_conv cx) ctxt ct
  1390 *}
  1391   | _ => Conv.all_conv ct)*}
  1391 
  1392 
  1392 text {* show example *}
  1393 text {*
  1393 
  1394 Here is an application of this new conversion:
  1394 text {*
  1395 
  1395 conversions inside a tactic: replace "true" in conclusion, "if true" in assumptions
  1396 @{ML_response_fake "if_true1_conv @{context} @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}" "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"}
  1396 *}
  1397 *}
  1397 
  1398 
  1398 ML {*
  1399 text {*
  1399 local open Conv 
  1400 Conversions can also be turned into a tactic with the @{ML CONVERSION}
       
  1401 tactical, and there are predefined conversionals to traverse a goal state
       
  1402 
       
  1403 @{term "\<And>x. P \<Longrightarrow> Q"}: 
       
  1404 
       
  1405 The conversional
       
  1406 @{ML Conv.params_conv} applies a conversion to @{term "P \<Longrightarrow> Q"},
       
  1407 @{ML Conv.prems_conv} applies a conversion to all premises in @{term "P \<Longrightarrow> Q"}, and
       
  1408 @{ML Conv.concl_conv} applies a conversion to the conclusion @{term Q} in @{term "P \<Longrightarrow> Q"}.
       
  1409 
       
  1410 Assume we want to apply @{ML all_true1_conv} only in the conclusion
       
  1411 of the goal, and @{ML if_true1_conv} should only be applied in the premises.
       
  1412 Here is a tactic doing exactly that:
       
  1413 *}
       
  1414 
       
  1415 ML {*local open Conv 
  1400 in
  1416 in
  1401 fun true1_tac ctxt =
  1417 val true1_tac = CSUBGOAL (fn (goal, i) =>
  1402   CONVERSION (
  1418   let val ctxt = ProofContext.init (Thm.theory_of_cterm goal)
  1403     Conv.params_conv ~1 (fn cx =>
  1419   in
  1404       (Conv.prems_conv ~1 (if_true1_conv cx)) then_conv
  1420     CONVERSION (
  1405         (Conv.concl_conv ~1 (all_true1_conv cx))) ctxt)
  1421       Conv.params_conv ~1 (fn cx =>
  1406 end
  1422         (Conv.prems_conv ~1 (if_true1_conv cx)) then_conv
  1407 *}
  1423           (Conv.concl_conv ~1 (all_true1_conv cx))) ctxt) i
  1408 
  1424   end)
  1409 text {* give example, show that the conditional rewriting works *}
  1425 end*}
       
  1426 
       
  1427 text {* FIXME: give example, show that the conditional rewriting works *}
       
  1428 
       
  1429 
       
  1430 text {*
       
  1431 Conversions are not restricted to work on certified terms only, they can also
       
  1432 be lifted to theorem transformers, i.e. functions mapping a theorem to a
       
  1433 theorem, by the help of @{ML Conv.fconv_rule}. As an example, consider the
       
  1434 conversion @{ML all_true1_conv} again:
       
  1435 
       
  1436 @{ML_response_fake "Conv.fconv_rule (all_true1_conv @{context}) @{lemma \"P \<or> (True \<and> \<not>P)\" by simp}" "P \<or> \<not>P"}
       
  1437 *}
  1410 
  1438 
  1411 
  1439 
  1412 
  1440 
  1413 
  1441 
  1414 
  1442