CookBook/Tactical.thy
changeset 147 6dafb0815ae6
parent 146 4aa8a80e37ff
child 148 84d1392186d3
equal deleted inserted replaced
146:4aa8a80e37ff 147:6dafb0815ae6
   725 text {*
   725 text {*
   726   then we have to be careful to not apply the tactic to the two subgoals produced by 
   726   then we have to be careful to not apply the tactic to the two subgoals produced by 
   727   the first goal. To do this can result in quite messy code. In contrast, 
   727   the first goal. To do this can result in quite messy code. In contrast, 
   728   the ``reverse application'' is easy to implement.
   728   the ``reverse application'' is easy to implement.
   729 
   729 
       
   730   (FIXME: mention @{ML "CSUBGOAL"})
       
   731 
   730   Of course, this example is contrived: there are much simpler methods available in 
   732   Of course, this example is contrived: there are much simpler methods available in 
   731   Isabelle for implementing a proof procedure analysing a goal according to its topmost
   733   Isabelle for implementing a proof procedure analysing a goal according to its topmost
   732   connective. These simpler methods use tactic combinators, which we will explain 
   734   connective. These simpler methods use tactic combinators, which we will explain 
   733   in the next section.
   735   in the next section.
   734 *}
   736 *}
  1317 
  1319 
  1318 section {* Conversions\label{sec:conversion} *}
  1320 section {* Conversions\label{sec:conversion} *}
  1319 
  1321 
  1320 text {*
  1322 text {*
  1321 
  1323 
  1322   Conversions are a ``thin'' layer on top of Isabelle's inference kernel, and 
  1324   Conversions are a thin layer on top of Isabelle's inference kernel, and 
  1323   can be viewed be as a controllable, bare-bone version of Isabelle's simplifier.
  1325   can be viewed be as a controllable, bare-bone version of Isabelle's simplifier.
  1324   A difference is that conversions simplify @{ML_type cterm}s, while teh simplifier
  1326   One difference between conversions and the simplifier is that the former
  1325   acts on theorems. The type for conversions is
  1327   act on @{ML_type cterm}s while the latter acts on @{ML_type thm}s. 
       
  1328   However, we will also show in this section how conversions can be applied
       
  1329   to theorems via tactics. The type for conversions is
  1326 *}
  1330 *}
  1327 
  1331 
  1328 ML{*type conv = Thm.cterm -> Thm.thm*}
  1332 ML{*type conv = Thm.cterm -> Thm.thm*}
  1329 
  1333 
  1330 text {*
  1334 text {*
  1331   whereby the theorem is always a meta-equality. A simple conversion is 
  1335   whereby the produced theorem is always a meta-equality. A simple conversion
  1332   the function @{ML "Conv.all_conv"}, which maps a @{ML_type cterm} to an instance of 
  1336   is the function @{ML "Conv.all_conv"}, which maps a @{ML_type cterm} to an
  1333   the (meta)reflexivity theorem. For example:
  1337   instance of the (meta)reflexivity theorem. For example:
  1334 
  1338 
  1335   @{ML_response_fake [display,gray]
  1339   @{ML_response_fake [display,gray]
  1336   "Conv.all_conv @{cterm \"Foo \<or> Bar\"}"
  1340   "Conv.all_conv @{cterm \"Foo \<or> Bar\"}"
  1337   "Foo \<or> Bar \<equiv> Foo \<or> Bar"}
  1341   "Foo \<or> Bar \<equiv> Foo \<or> Bar"}
  1338 
  1342 
  1339   Another simple conversion is @{ML Conv.no_conv} which always raises the exception @{ML CTERM}
  1343   Another simple conversion is @{ML Conv.no_conv} which always raises the 
       
  1344   exception @{ML CTERM}.
  1340 
  1345 
  1341   @{ML_response_fake [display,gray]
  1346   @{ML_response_fake [display,gray]
  1342   "Conv.no_conv @{cterm True}" 
  1347   "Conv.no_conv @{cterm True}" 
  1343   "*** Exception- CTERM (\"no conversion\", []) raised"}
  1348   "*** Exception- CTERM (\"no conversion\", []) raised"}
  1344 
  1349 
  1353 in
  1358 in
  1354   Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
  1359   Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
  1355 end"
  1360 end"
  1356   "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"}
  1361   "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"}
  1357 
  1362 
  1358   Note that the actual response in the example is @{term "2 + 10 \<equiv> 2 + (10::nat)"}, 
  1363   Note that the actual response in this example is @{term "2 + 10 \<equiv> 2 + (10::nat)"}, 
  1359   since the pretty-printer of @{ML_type cterm}s already beta-normalises terms.
  1364   since the pretty printer for @{ML_type cterm}s already beta-normalises terms.
  1360   However, we can by how we constructed the term (using the function 
  1365   But by the way how we constructed the term (using the function 
  1361   @{ML Thm.capply}, which is the application @{ML $} for @{ML_type cterm})
  1366   @{ML Thm.capply}, which is the application @{ML $} for @{ML_type cterm}s),
  1362   that the left-hand side must contain beta-redexes.
  1367   we can be sure the left-hand side must contain beta-redexes. Indeed
       
  1368   if we obtain the ``raw'' representation of the produced theorem, we
       
  1369   can see the difference:
       
  1370 
       
  1371   @{ML_response [display,gray]
       
  1372 "let
       
  1373   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
       
  1374   val two = @{cterm \"2::nat\"}
       
  1375   val ten = @{cterm \"10::nat\"}
       
  1376 in
       
  1377   #prop (rep_thm 
       
  1378           (Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)))
       
  1379 end"
       
  1380 "Const (\"==\",\<dots>) $ 
       
  1381   (Abs (\"x\",\<dots>,Abs (\"y\",\<dots>,\<dots>)) $\<dots>$\<dots>) $ 
       
  1382     (Const (\"HOL.plus_class.plus\",\<dots>) $ \<dots> $ \<dots>)"} 
  1363 
  1383 
  1364   The argument @{ML true} in @{ML Thm.beta_conversion} indicates that 
  1384   The argument @{ML true} in @{ML Thm.beta_conversion} indicates that 
  1365   the right-hand side should be fully beta-normalised. If @{ML false} is
  1385   the right-hand side will be fully beta-normalised. If instead 
  1366   given, then only a beta-reduction is performed on the outer-most level.
  1386   @{ML false} is given, then only a single beta-reduction is performed 
  1367   For example
  1387   on the outer-most level. For example
  1368 
  1388 
  1369   @{ML_response_fake [display,gray]
  1389   @{ML_response_fake [display,gray]
  1370   "let
  1390   "let
  1371   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1391   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1372   val two = @{cterm \"2::nat\"}
  1392   val two = @{cterm \"2::nat\"}
  1374   Thm.beta_conversion false (Thm.capply add two)
  1394   Thm.beta_conversion false (Thm.capply add two)
  1375 end"
  1395 end"
  1376   "((\<lambda>x y. x + y) 2) \<equiv> \<lambda>y. 2 + y"} 
  1396   "((\<lambda>x y. x + y) 2) \<equiv> \<lambda>y. 2 + y"} 
  1377 
  1397 
  1378   Again, we actually see as output only the fully normalised term 
  1398   Again, we actually see as output only the fully normalised term 
  1379   @{term "\<lambda>y. 2 + y"}.
  1399   @{text "\<lambda>y. 2 + y"}.
  1380 
  1400 
  1381   The main point of conversions is that they can be used for rewriting terms.
  1401   The main point of conversions is that they can be used for rewriting
  1382   For this you can use the function @{ML "Conv.rewr_conv"}. Suppose we want 
  1402   @{ML_type cterm}s. To do this you can use the function @{ML
  1383   to rewrite a term according to the (meta)equation:
  1403   "Conv.rewr_conv"} which expects a meta-equation as an argument. Suppose we
  1384 
  1404   want to rewrite a @{ML_type cterm} according to the (meta)equation:
  1385 *}
  1405 *}
  1386 
  1406 
  1387 lemma true_conj1: "True \<and> P \<equiv> P" by simp
  1407 lemma true_conj1: "True \<and> P \<equiv> P" by simp
  1388 
  1408 
  1389 text {* 
  1409 text {* 
  1390   then we can use it in order to rewrite @{term "True \<and> (Foo \<longrightarrow> Bar)"}:
  1410   You can see how this function works with the example 
       
  1411   @{term "True \<and> (Foo \<longrightarrow> Bar)"}:
  1391 
  1412 
  1392   @{ML_response_fake [display,gray]
  1413   @{ML_response_fake [display,gray]
  1393 "let 
  1414 "let 
  1394   val ctrm =  @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"}
  1415   val ctrm =  @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"}
  1395 in
  1416 in
  1396   Conv.rewr_conv @{thm true_conj1} ctrm
  1417   Conv.rewr_conv @{thm true_conj1} ctrm
  1397 end"
  1418 end"
  1398   "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"}
  1419   "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"}
  1399 
  1420 
  1400   The function @{ML Conv.rewr_conv} only does rewriting on the outer-most
  1421   Note, however, that the function @{ML Conv.rewr_conv} only rewrites the 
  1401   level, otherwise it raises the exception @{ML CTERM}.
  1422   outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match the 
       
  1423   left-hand side of the theorem, then  @{ML Conv.rewr_conv} raises 
       
  1424   the exception @{ML CTERM}.
  1402 
  1425 
  1403   This very primitive way of rewriting can be made more powerful by
  1426   This very primitive way of rewriting can be made more powerful by
  1404   combining several conversions into one. For this you can use conversion
  1427   combining several conversions into one. For this you can use conversion
  1405   combinators. The simplest conversion combinator is @{ML then_conv}, 
  1428   combinators. The simplest conversion combinator is @{ML then_conv}, 
  1406   which applies one conversion after another. For example
  1429   which applies one conversion after another. For example
  1407 
  1430 
  1408   @{ML_response_fake [display,gray]
  1431   @{ML_response_fake [display,gray]
  1409 "let
  1432 "let
  1410   val conv1 = Thm.beta_conversion true
  1433   val conv1 = Thm.beta_conversion false
  1411   val conv2 = Conv.rewr_conv @{thm true_conj1}
  1434   val conv2 = Conv.rewr_conv @{thm true_conj1}
  1412   val ctrm = Thm.capply (@{cterm \"\<lambda>x. x \<and> False\"}) (@{cterm \"True\"})
  1435   val ctrm = Thm.capply @{cterm \"\<lambda>x. x \<and> False\"} @{cterm \"True\"}
  1413 in
  1436 in
  1414   (conv1 then_conv conv2) ctrm
  1437   (conv1 then_conv conv2) ctrm
  1415 end"
  1438 end"
  1416   "(\<lambda>x. x \<and> False) True \<equiv> False"}
  1439   "(\<lambda>x. x \<and> False) True \<equiv> False"}
  1417 
  1440 
       
  1441   where we first beta-reduce the term and then rewrite according to
       
  1442   @{thm [source] true_conj1}. 
       
  1443 
  1418   The conversion combinator @{ML else_conv} tries out the 
  1444   The conversion combinator @{ML else_conv} tries out the 
  1419   first one, and if it does not apply, tries the second. For example 
  1445   first one, and if it does not apply, tries the second. For example 
  1420 
  1446 
  1421   @{ML_response_fake [display,gray]
  1447   @{ML_response_fake [display,gray]
  1422 "let
  1448 "let
  1423   val conv = Conv.rewr_conv @{thm true_conj1} 
  1449   val conv = Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv
  1424              else_conv Conv.all_conv
       
  1425   val ctrm1 = @{cterm \"True \<and> Q\"}
  1450   val ctrm1 = @{cterm \"True \<and> Q\"}
  1426   val ctrm2 = @{cterm \"P \<or> (True \<and> Q)\"}
  1451   val ctrm2 = @{cterm \"P \<or> (True \<and> Q)\"}
  1427 in
  1452 in
  1428   (conv ctrm1, conv ctrm2)
  1453   (conv ctrm1, conv ctrm2)
  1429 end"
  1454 end"
  1430 "(True \<and> Q \<equiv> Q, 
  1455 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"}
  1431  P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"}
       
  1432 
  1456 
  1433   Here the conversion of @{thm [source] true_conj1} only applies
  1457   Here the conversion of @{thm [source] true_conj1} only applies
  1434   in the first case, but fails in the second. The whole conversion
  1458   in the first case, but fails in the second. The whole conversion
  1435   does not fail because the combinator @{ML else_conv} will then 
  1459   does not fail, however, because the combinator @{ML else_conv} will then 
  1436   try out @{ML Conv.all_conv}, which allways succeeds.
  1460   try out @{ML Conv.all_conv}, which always succeeds.
  1437 
  1461 
  1438   The combinator @{ML Conv.arg_conv} will apply the conversion on
  1462   Apart from the function @{ML beta_conversion in Thm}, which able to fully
  1439   the first argument, taht is the term must be of the form 
  1463   beta-normalise a term, the restriction of conversions so far is that they
  1440   @{ML "t1 $ t2" for t1 t2} and the conversion is applied to @{text t2}.
  1464   only apply to the outer-most level of a @{ML_type cterm}. In what follows we
  1441   For example
  1465   will lift this restriction. The combinator @{ML Conv.arg_conv} will apply
       
  1466   the conversion on the first argument of an application, that is the term
       
  1467   must be of the form @{ML "t1 $ t2" for t1 t2} and the conversion is applied
       
  1468   to @{text t2}.  For example
  1442 
  1469 
  1443   @{ML_response_fake [display,gray]
  1470   @{ML_response_fake [display,gray]
  1444 "let 
  1471 "let 
  1445   val conv = Conv.rewr_conv @{thm true_conj1}
  1472   val conv = Conv.rewr_conv @{thm true_conj1}
  1446   val ctrm = @{cterm \"P \<or> (True \<and> Q)\"}
  1473   val ctrm = @{cterm \"P \<or> (True \<and> Q)\"}
  1447 in
  1474 in
  1448   Conv.arg_conv conv ctrm
  1475   Conv.arg_conv conv ctrm
  1449 end"
  1476 end"
  1450 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
  1477 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
  1451 
  1478 
  1452   The reason for this behaviour is that @{text "(op \<or>)"} expects two arguments
  1479   The reason for this behaviour is that @{text "(op \<or>)"} expects two
  1453   and so is of the form @{text "Const \<dots> $ t1 $ t2"}. The conversion is then 
  1480   arguments.  So the term must be of the form @{text "Const \<dots> $ t1 $ t2"}. The
  1454   applied to @{text "t2"} which stands for @{term "True \<and> Q"}.
  1481   conversion is then applied to @{text "t2"} which in the example above
  1455 
  1482   stands for @{term "True \<and> Q"}.
  1456 *}
  1483 
  1457 
  1484   The function @{ML Conv.abs_conv} applies a conversion under an abstractions.
  1458 
  1485   For example:
  1459 text {*
  1486 
  1460   To begin with, let us assumes we want to simplify with the rewrite rule
  1487   @{ML_response_fake [display,gray]
  1461   @{text true_conj1}. As a conversion, this may look as follows:
  1488 "let 
  1462 *}
  1489   val conv = K (Conv.rewr_conv @{thm true_conj1}) 
  1463 
  1490   val ctrm = @{cterm \"\<lambda>P. True \<and> P \<and> Foo\"}
  1464 
  1491 in
  1465 ML{*fun all_true1_conv ctxt ct =
  1492   Conv.abs_conv conv @{context} ctrm
  1466   (case Thm.term_of ct of
  1493 end"
       
  1494   "\<lambda>P. True \<and> P \<and> Foo \<equiv> \<lambda>P. P \<and> Foo"}
       
  1495   
       
  1496   The conversion that goes under an application is
       
  1497   @{ML Conv.combination_conv}. It expects two conversions, which each of them
       
  1498   is applied to the corresponding ``branch'' of the application. 
       
  1499 
       
  1500   We can now apply all these functions in a
       
  1501   conversion that recursively descends a term and applies a conversion in all
       
  1502   possible positions.
       
  1503 *}
       
  1504 
       
  1505 ML %linenosgray{*fun all_true1_conv ctxt ctrm =
       
  1506   case (Thm.term_of ctrm) of
  1467     @{term "op \<and>"} $ @{term True} $ _ => 
  1507     @{term "op \<and>"} $ @{term True} $ _ => 
  1468       (Conv.arg_conv (all_true1_conv ctxt) then_conv
  1508       (Conv.arg_conv (all_true1_conv ctxt) then_conv
  1469         Conv.rewr_conv @{thm true_conj1}) ct
  1509          Conv.rewr_conv @{thm true_conj1}) ctrm
  1470   | _ $ _ => Conv.combination_conv (all_true1_conv ctxt)
  1510   | _ $ _ => Conv.combination_conv 
  1471       (all_true1_conv ctxt) ct
  1511                  (all_true1_conv ctxt) (all_true1_conv ctxt) ctrm
  1472   | Abs _ => Conv.abs_conv (fn (_, cx) => all_true1_conv cx) ctxt ct
  1512   | Abs _ => Conv.abs_conv (fn (_, ctxt) => all_true1_conv ctxt) ctxt ctrm
  1473   | _ => Conv.all_conv ct)*}
  1513   | _ => Conv.all_conv ctrm*}
  1474 
  1514 
  1475 text {*
  1515 text {*
  1476   Here is this conversion in action:
  1516   This functions descends under applications (Line 6 and 7) and abstractions 
       
  1517   (Line 8); and ``fires'' if the outer-most constant is an @{text "True \<and> \<dots>"}
       
  1518   (Lines 3-5); otherwise it leaves the term unchanged (Line 9). To see this 
       
  1519   conversion in action, consider the following example.
       
  1520 
       
  1521 @{ML_response_fake [display,gray]
       
  1522 "let
       
  1523   val ctxt = @{context}
       
  1524   val ctrm = @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}
       
  1525 in
       
  1526   all_true1_conv ctxt ctrm
       
  1527 end"
       
  1528   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
       
  1529 
       
  1530   To see how much control you have about rewriting via conversions, let us 
       
  1531   make the task a bit more complicated by rewriting according to the rule
       
  1532   @{text true_conj1}, but only in the first arguments of @{term If}s. The 
       
  1533   the conversion should be as follows.
       
  1534 *}
       
  1535 
       
  1536 ML{*fun if_true1_conv ctxt ctrm =
       
  1537   case Thm.term_of ctrm of
       
  1538     Const (@{const_name If}, _) $ _ =>
       
  1539       Conv.arg_conv (all_true1_conv ctxt) ctrm
       
  1540   | _ $ _ => Conv.combination_conv 
       
  1541                         (if_true1_conv ctxt) (if_true1_conv ctxt) ctrm
       
  1542   | Abs _ => Conv.abs_conv (fn (_, ctxt) => if_true1_conv ctxt) ctxt ctrm
       
  1543   | _ => Conv.all_conv ctrm *}
       
  1544 
       
  1545 text {*
       
  1546   Here is an application of this conversion:
  1477 
  1547 
  1478   @{ML_response_fake [display,gray]
  1548   @{ML_response_fake [display,gray]
  1479   "all_true1_conv @{context}
  1549 "let
  1480   @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}"
  1550   val ctxt = @{context}
  1481   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
  1551   val ctrm = 
  1482 
  1552      @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}
  1483   Now, let us make the task a bit more complicated by rewriting according to the rule
  1553 in
  1484   @{text true_conj1}, but only in the first arguments of @{term If}:
  1554   if_true1_conv ctxt ctrm
  1485 *}
  1555 end"
  1486 
  1556 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False 
  1487 ML{*fun if_true1_conv ctxt ct =
  1557 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"}
  1488   (case Thm.term_of ct of
  1558 *}
  1489     Const (@{const_name If}, _) $ _ =>
  1559 
  1490       Conv.arg_conv (all_true1_conv ctxt) ct
  1560 text {*
  1491   | _ $ _ => Conv.combination_conv (if_true1_conv ctxt)
  1561   So far we only applied conversions to @{ML_type cterm}s. Conversions can, however, 
  1492       (if_true1_conv ctxt) ct
  1562   also work on theorems using the function @{ML "Conv.fconv_rule"}. As an example, 
  1493   | Abs _ => Conv.abs_conv (fn (_, cx) => if_true1_conv cx) ctxt ct
  1563   consider @{ML all_true1_conv} and the lemma:
  1494   | _ => Conv.all_conv ct)*}
  1564 *}
  1495 
  1565 
  1496 text {*
  1566 lemma foo_test: "P \<or> (True \<and> \<not>P)" by simp
  1497   Here is an application of this conversion:
  1567 
       
  1568 text {*
       
  1569   Using the conversion you can transform this theorem into a new theorem
       
  1570   as follows
  1498 
  1571 
  1499   @{ML_response_fake [display,gray]
  1572   @{ML_response_fake [display,gray]
  1500   "if_true1_conv @{context}
  1573   "Conv.fconv_rule (all_true1_conv @{context}) @{thm foo_test}" 
  1501   @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}"
  1574   "?P \<or> \<not> ?P"}
  1502   "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"}
  1575 
  1503 *}
  1576   Finally, conversions can also be turned into tactics and then applied to
  1504 
  1577   goal states. This can be done with the help of the function @{ML CONVERSION},
  1505 text {*
  1578   and also some predefined conversion combinator which traverse a goal
  1506   Conversions can also be turned into a tactic with the @{ML CONVERSION}
  1579   state. The combinators for the goal state are: @{ML Conv.params_conv} for
  1507   tactical, and there are predefined conversionals to traverse a goal state.
  1580   going under parameters (i.e.~where goals are of the form @{text "\<And>x. P \<Longrightarrow>
  1508   Given a state @{term "\<And>x. P \<Longrightarrow> Q"},  the conversional
  1581   Q"}); the function @{ML Conv.prems_conv} for applying the conversion to all
  1509   @{ML Conv.params_conv} applies a conversion to @{term "P \<Longrightarrow> Q"};
  1582   premises of a goal, and @{ML Conv.concl_conv} for applying the conversion to
  1510   given a state @{term "\<lbrakk> P1; P2 \<rbrakk> \<Longrightarrow> Q"},
  1583   the conclusion of a goal.
  1511   the conversional @{ML Conv.prems_conv} applies a conversion to the premises
       
  1512   @{term P1} and @{term P2}, and @{ML Conv.concl_conv} applies a conversion to
       
  1513   the conclusion @{term Q}.
       
  1514 
  1584 
  1515   Assume we want to apply @{ML all_true1_conv} only in the conclusion
  1585   Assume we want to apply @{ML all_true1_conv} only in the conclusion
  1516   of the goal, and @{ML if_true1_conv} should only be applied in the premises.
  1586   of the goal, and @{ML if_true1_conv} should only be applied in the premises.
  1517   Here is a tactic doing exactly that:
  1587   Here is a tactic doing exactly that:
  1518 *}
  1588 *}
  1519 
  1589 
  1520 ML{*val true1_tac = CSUBGOAL (fn (goal, i) =>
  1590 ML{*val true1_tac = CSUBGOAL (fn (goal, i) =>
  1521   let val ctxt = ProofContext.init (Thm.theory_of_cterm goal)
  1591   let 
       
  1592     val ctxt = ProofContext.init (Thm.theory_of_cterm goal)
  1522   in
  1593   in
  1523     CONVERSION (
  1594     CONVERSION 
  1524       Conv.params_conv ~1 (fn cx =>
  1595       (Conv.params_conv ~1 (fn ctxt =>
  1525         (Conv.prems_conv ~1 (if_true1_conv cx)) then_conv
  1596         (Conv.prems_conv ~1 (if_true1_conv ctxt)) then_conv
  1526           Conv.concl_conv ~1 (all_true1_conv cx)) ctxt) i
  1597           Conv.concl_conv ~1 (all_true1_conv ctxt)) ctxt) i
  1527   end)*}
  1598   end)*}
  1528 
  1599 
  1529 text {* 
  1600 text {* 
  1530   To demonstrate this tactic, consider the following example:
  1601   We call the conversions with the argument @{ML "~1"} in order to 
       
  1602   analyse all parameters, premises and conclusions. If we call it with 
       
  1603   a non-negative number, say @{text n}, then these conversions will 
       
  1604   only be called on @{text n} premises (similar for parameters and
       
  1605   conclusions). To test the tactic, consider the proof
  1531 *}
  1606 *}
  1532 
  1607 
  1533 lemma
  1608 lemma
  1534   "if True \<and> P then P else True \<and> False \<Longrightarrow>
  1609   "if True \<and> P then P else True \<and> False \<Longrightarrow>
  1535   (if True \<and> Q then Q else P) \<longrightarrow> True \<and> (True \<and> Q)"
  1610   (if True \<and> Q then Q else P) \<longrightarrow> True \<and> (True \<and> Q)"
  1536 apply(tactic {* true1_tac 1 *})
  1611 apply(tactic {* true1_tac 1 *})
  1537 txt {* \begin{minipage}{\textwidth}
  1612 txt {* where the tactic yields the goal state
       
  1613 
       
  1614        \begin{minipage}{\textwidth}
  1538        @{subgoals [display]} 
  1615        @{subgoals [display]} 
  1539        \end{minipage} *}
  1616        \end{minipage} *}
  1540 (*<*)oops(*>*)
  1617 (*<*)oops(*>*)
  1541 
  1618 
  1542 text {*
  1619 text {*
  1543   Conversions are not restricted to work on certified terms only, they can also
  1620   To sum up this section, conversions are not as powerful as the simplifier
  1544   be lifted to theorem transformers, i.e. functions mapping a theorem to a
  1621   and simprocs; the advantage of conversions, however, is that you never have
  1545   theorem, by the help of @{ML Conv.fconv_rule}. As an example, consider the
  1622   to worry about non-termination.
  1546   conversion @{ML all_true1_conv} again:
       
  1547 
       
  1548   @{ML_response_fake [display,gray]
       
  1549   "Conv.fconv_rule (all_true1_conv @{context}) @{lemma \"P \<or> (True \<and> \<not>P)\" by simp}" 
       
  1550   "P \<or> \<not>P"}
       
  1551 
  1623 
  1552   \begin{readmore}
  1624   \begin{readmore}
  1553   See @{ML_file "Pure/conv.ML"} for more information about conversion combinators. 
  1625   See @{ML_file "Pure/conv.ML"} for more information about conversion combinators. 
  1554   Further conversions are defined in  @{ML_file "Pure/thm.ML"},
  1626   Further conversions are defined in  @{ML_file "Pure/thm.ML"},
  1555   @{ML_file "Pure/drule.ML"} and @{ML_file "Pure/meta_simplifier.ML"}.
  1627   @{ML_file "Pure/drule.ML"} and @{ML_file "Pure/meta_simplifier.ML"}.