|   1318 section {* Conversions\label{sec:conversion} *} |   1318 section {* Conversions\label{sec:conversion} *} | 
|   1319  |   1319  | 
|   1320 text {* |   1320 text {* | 
|   1321  |   1321  | 
|   1322   Conversions are a ``thin'' layer on top of Isabelle's inference kernel, and  |   1322   Conversions are a ``thin'' layer on top of Isabelle's inference kernel, and  | 
|   1323   may be seen as a controllable, bare-bone version of Isabelle's simplifier. |   1323   can be viewed be as a controllable, bare-bone version of Isabelle's simplifier. | 
|   1324   They are meta-equalities depending on some input term. Their type is |   1324   A difference is that conversions simplify @{ML_type cterm}s, while teh simplifier | 
|   1325   as follows: |   1325   acts on theorems. The type for conversions is | 
|   1326 *} |   1326 *} | 
|   1327  |   1327  | 
|   1328 ML{*type conv = Thm.cterm -> Thm.thm*} |   1328 ML{*type conv = Thm.cterm -> Thm.thm*} | 
|   1329  |   1329  | 
|   1330 text {* |   1330 text {* | 
|   1331   The simplest two conversions are @{ML "Conv.all_conv"}, which maps a  |   1331   whereby the theorem is always a meta-equality. A simple conversion is  | 
|   1332   term to an instance of the reflexivity theorem, and  |   1332   the function @{ML "Conv.all_conv"}, which maps a @{ML_type cterm} to an instance of  | 
|   1333   @{ML "Conv.no_conv"}, which always fails: |   1333   the (meta)reflexivity theorem. For example: | 
|   1334  |   1334  | 
|   1335   @{ML_response_fake [display,gray] |   1335   @{ML_response_fake [display,gray] | 
|   1336   "Conv.all_conv @{cterm True}" "True \<equiv> True"} |   1336   "Conv.all_conv @{cterm \"Foo \<or> Bar\"}" | 
|         |   1337   "Foo \<or> Bar \<equiv> Foo \<or> Bar"} | 
|         |   1338  | 
|         |   1339   Another simple conversion is @{ML Conv.no_conv} which always raises the exception @{ML CTERM} | 
|   1337  |   1340  | 
|   1338   @{ML_response_fake [display,gray] |   1341   @{ML_response_fake [display,gray] | 
|   1339   "Conv.no_conv @{cterm True}"  |   1342   "Conv.no_conv @{cterm True}"  | 
|   1340   "*** Exception- CTERM (\"no conversion\", []) raised"} |   1343   "*** Exception- CTERM (\"no conversion\", []) raised"} | 
|   1341  |   1344  | 
|   1342   A further basic conversion is, for example, @{ML "Thm.beta_conversion"}: |   1345   A more interesting conversion is the function @{ML "Thm.beta_conversion"}: it  | 
|         |   1346   produces an equation between a term and its beta-normal form. For example | 
|   1343  |   1347  | 
|   1344   @{ML_response_fake [display,gray] |   1348   @{ML_response_fake [display,gray] | 
|   1345   "Thm.beta_conversion true @{cterm \"(\<lambda>x. x \<or> False) True\"}" |   1349   "let | 
|   1346   "(\<lambda>x. x \<or> False) True \<equiv> True \<or> False"} |   1350   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"} | 
|   1347  |   1351   val two = @{cterm \"2::nat\"} | 
|   1348   User-defined rewrite rules can be applied by the conversion |   1352   val ten = @{cterm \"10::nat\"} | 
|   1349   @{ML "Conv.rewr_conv"}. Consider, for example, the following rule: |   1353 in | 
|         |   1354   Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten) | 
|         |   1355 end" | 
|         |   1356   "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"} | 
|         |   1357  | 
|         |   1358   Note that the actual response in the example is @{term "2 + 10 \<equiv> 2 + (10::nat)"},  | 
|         |   1359   since the pretty-printer of @{ML_type cterm}s already beta-normalises terms. | 
|         |   1360   However, we can by how we constructed the term (using the function  | 
|         |   1361   @{ML Thm.capply}, which is the application @{ML $} for @{ML_type cterm}) | 
|         |   1362   that the left-hand side must contain beta-redexes. | 
|         |   1363  | 
|         |   1364   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 | 
|         |   1366   given, then only a beta-reduction is performed on the outer-most level. | 
|         |   1367   For example | 
|         |   1368  | 
|         |   1369   @{ML_response_fake [display,gray] | 
|         |   1370   "let | 
|         |   1371   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"} | 
|         |   1372   val two = @{cterm \"2::nat\"} | 
|         |   1373 in | 
|         |   1374   Thm.beta_conversion false (Thm.capply add two) | 
|         |   1375 end" | 
|         |   1376   "((\<lambda>x y. x + y) 2) \<equiv> \<lambda>y. 2 + y"}  | 
|         |   1377  | 
|         |   1378   Again, we actually see as output only the fully normalised term  | 
|         |   1379   @{term "\<lambda>y. 2 + y"}. | 
|         |   1380  | 
|         |   1381   The main point of conversions is that they can be used for rewriting terms. | 
|         |   1382   For this you can use the function @{ML "Conv.rewr_conv"}. Suppose we want  | 
|         |   1383   to rewrite a term according to the (meta)equation: | 
|         |   1384  | 
|   1350 *} |   1385 *} | 
|   1351  |   1386  | 
|   1352 lemma true_conj1: "True \<and> P \<equiv> P" by simp |   1387 lemma true_conj1: "True \<and> P \<equiv> P" by simp | 
|   1353  |   1388  | 
|   1354 text {* |   1389 text {*  | 
|   1355   Here is how this rule can be used for rewriting: |   1390   then we can use it in order to rewrite @{term "True \<and> (Foo \<longrightarrow> Bar)"}: | 
|   1356  |   1391  | 
|   1357   @{ML_response_fake [display,gray] |   1392   @{ML_response_fake [display,gray] | 
|   1358   "Conv.rewr_conv @{thm true_conj1} @{cterm \"True \<or> False\"}" |   1393 "let  | 
|   1359   "True \<and> False \<equiv> False"} |   1394   val ctrm =  @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"} | 
|   1360 *} |   1395 in | 
|   1361  |   1396   Conv.rewr_conv @{thm true_conj1} ctrm | 
|   1362 text {* |   1397 end" | 
|   1363   Basic conversions can be combined with a number of conversionals, i.e. |   1398   "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"} | 
|   1364   conversion combinators: |   1399  | 
|         |   1400   The function @{ML Conv.rewr_conv} only does rewriting on the outer-most | 
|         |   1401   level, otherwise it raises the exception @{ML CTERM}. | 
|         |   1402  | 
|         |   1403   This very primitive way of rewriting can be made more powerful by | 
|         |   1404   combining several conversions into one. For this you can use conversion | 
|         |   1405   combinators. The simplest conversion combinator is @{ML then_conv},  | 
|         |   1406   which applies one conversion after another. For example | 
|   1365  |   1407  | 
|   1366   @{ML_response_fake [display,gray] |   1408   @{ML_response_fake [display,gray] | 
|   1367   "(Thm.beta_conversion true then_conv Conv.rewr_conv @{thm true_conj1}) |   1409 "let | 
|   1368   @{cterm \"(\<lambda>x. x \<and> False) True\"}" |   1410   val conv1 = Thm.beta_conversion true | 
|         |   1411   val conv2 = Conv.rewr_conv @{thm true_conj1} | 
|         |   1412   val ctrm = Thm.capply (@{cterm \"\<lambda>x. x \<and> False\"}) (@{cterm \"True\"}) | 
|         |   1413 in | 
|         |   1414   (conv1 then_conv conv2) ctrm | 
|         |   1415 end" | 
|   1369   "(\<lambda>x. x \<and> False) True \<equiv> False"} |   1416   "(\<lambda>x. x \<and> False) True \<equiv> False"} | 
|   1370  |   1417  | 
|         |   1418   The conversion combinator @{ML else_conv} tries out the  | 
|         |   1419   first one, and if it does not apply, tries the second. For example  | 
|         |   1420  | 
|   1371   @{ML_response_fake [display,gray] |   1421   @{ML_response_fake [display,gray] | 
|   1372   "(Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv) |   1422 "let | 
|   1373   @{cterm \"P \<or> (True \<and> Q)\"}" |   1423   val conv = Conv.rewr_conv @{thm true_conj1}  | 
|   1374   "P \<or> (True \<and> Q) \<equiv> P \<or> (True \<and> Q)"} |   1424              else_conv Conv.all_conv | 
|         |   1425   val ctrm1 = @{cterm \"True \<and> Q\"} | 
|         |   1426   val ctrm2 = @{cterm \"P \<or> (True \<and> Q)\"} | 
|         |   1427 in | 
|         |   1428   (conv ctrm1, conv ctrm2) | 
|         |   1429 end" | 
|         |   1430 "(True \<and> Q \<equiv> Q,  | 
|         |   1431  P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} | 
|         |   1432  | 
|         |   1433   Here the conversion of @{thm [source] true_conj1} only applies | 
|         |   1434   in the first case, but fails in the second. The whole conversion | 
|         |   1435   does not fail because the combinator @{ML else_conv} will then  | 
|         |   1436   try out @{ML Conv.all_conv}, which allways succeeds. | 
|         |   1437  | 
|         |   1438   The combinator @{ML Conv.arg_conv} will apply the conversion on | 
|         |   1439   the first argument, taht is the term must be of the form  | 
|         |   1440   @{ML "t1 $ t2" for t1 t2} and the conversion is applied to @{text t2}. | 
|         |   1441   For example | 
|   1375  |   1442  | 
|   1376   @{ML_response_fake [display,gray] |   1443   @{ML_response_fake [display,gray] | 
|   1377   "Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) |   1444 "let  | 
|   1378   @{cterm \"P \<or> (True \<and> Q)\"}" |   1445   val conv = Conv.rewr_conv @{thm true_conj1} | 
|   1379   "P \<or> (True \<and> Q) \<equiv> P \<or> Q"} |   1446   val ctrm = @{cterm \"P \<or> (True \<and> Q)\"} | 
|   1380  |   1447 in | 
|   1381   \begin{readmore} |   1448   Conv.arg_conv conv ctrm | 
|   1382   See @{ML_file "Pure/conv.ML"} for more conversionals. Further basic conversions |   1449 end" | 
|   1383   can be found in, for example, @{ML_file "Pure/thm.ML"}, |   1450 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"} | 
|   1384   @{ML_file "Pure/drule.ML"}, and @{ML_file "Pure/meta_simplifier.ML"}. |   1451  | 
|   1385   \end{readmore} |   1452   The reason for this behaviour is that @{text "(op \<or>)"} expects two arguments | 
|   1386  |   1453   and so is of the form @{text "Const \<dots> $ t1 $ t2"}. The conversion is then  | 
|   1387   We will demonstrate this feature in the following example. |   1454   applied to @{text "t2"} which stands for @{term "True \<and> Q"}. | 
|   1388  |   1455  | 
|   1389   To begin with, let's assumes we want to simplify with the rewrite rule |   1456 *} | 
|         |   1457  | 
|         |   1458  | 
|         |   1459 text {* | 
|         |   1460   To begin with, let us assumes we want to simplify with the rewrite rule | 
|   1390   @{text true_conj1}. As a conversion, this may look as follows: |   1461   @{text true_conj1}. As a conversion, this may look as follows: | 
|   1391 *} |   1462 *} | 
|         |   1463  | 
|   1392  |   1464  | 
|   1393 ML{*fun all_true1_conv ctxt ct = |   1465 ML{*fun all_true1_conv ctxt ct = | 
|   1394   (case Thm.term_of ct of |   1466   (case Thm.term_of ct of | 
|   1395     @{term "op \<and>"} $ @{term True} $ _ =>  |   1467     @{term "op \<and>"} $ @{term True} $ _ =>  | 
|   1396       (Conv.arg_conv (all_true1_conv ctxt) then_conv |   1468       (Conv.arg_conv (all_true1_conv ctxt) then_conv |