1316 *} |
1316 *} |
1317 |
1317 |
1318 section {* Conversions\label{sec:conversion} *} |
1318 section {* Conversions\label{sec:conversion} *} |
1319 |
1319 |
1320 text {* |
1320 text {* |
1321 Conversions are meta-equalities depending on some input term. Their type is |
1321 |
1322 as follows: |
1322 Conversions are a ``thin'' layer on top of Isabelle's inference kernel, and |
1323 *} |
1323 may be seen as a controllable, bare-bone version of Isabelle's simplifier. |
1324 |
1324 They are meta-equalities depending on some input term. Their type is |
1325 ML {*type conv = Thm.cterm -> Thm.thm*} |
1325 as follows: |
1326 |
1326 *} |
1327 text {* |
1327 |
1328 The simplest two conversions are @{ML "Conv.all_conv"}, which maps a term to an instance of the reflexivity theorem, and @{ML "Conv.no_conv"}, which always fails: |
1328 ML{*type conv = Thm.cterm -> Thm.thm*} |
1329 |
1329 |
1330 @{ML_response_fake "Conv.all_conv @{cterm True}" "True \<equiv> True"} |
1330 text {* |
1331 |
1331 The simplest two conversions are @{ML "Conv.all_conv"}, which maps a |
1332 @{ML_response_fake "Conv.no_conv @{cterm True}" "*** Exception- CTERM (\"no conversion\", []) raised"} |
1332 term to an instance of the reflexivity theorem, and |
1333 |
1333 @{ML "Conv.no_conv"}, which always fails: |
1334 A further basic conversion is, for example, @{ML "Thm.beta_conversion"}: |
1334 |
1335 |
1335 @{ML_response_fake [display,gray] |
1336 @{ML_response_fake "Thm.beta_conversion true @{cterm \"(\<lambda>x. x \<or> False) True\"}" |
1336 "Conv.all_conv @{cterm True}" "True \<equiv> True"} |
1337 "(\<lambda>x. x \<or> False) True \<equiv> True \<or> False"} |
1337 |
1338 |
1338 @{ML_response_fake [display,gray] |
1339 User-defined rewrite rules can be applied by the conversion |
1339 "Conv.no_conv @{cterm True}" |
1340 @{ML "Conv.rewr_conv"}. Consider, for example, the following rule: |
1340 "*** Exception- CTERM (\"no conversion\", []) raised"} |
|
1341 |
|
1342 A further basic conversion is, for example, @{ML "Thm.beta_conversion"}: |
|
1343 |
|
1344 @{ML_response_fake [display,gray] |
|
1345 "Thm.beta_conversion true @{cterm \"(\<lambda>x. x \<or> False) True\"}" |
|
1346 "(\<lambda>x. x \<or> False) True \<equiv> True \<or> False"} |
|
1347 |
|
1348 User-defined rewrite rules can be applied by the conversion |
|
1349 @{ML "Conv.rewr_conv"}. Consider, for example, the following rule: |
1341 *} |
1350 *} |
1342 |
1351 |
1343 lemma true_conj1: "True \<and> P \<equiv> P" by simp |
1352 lemma true_conj1: "True \<and> P \<equiv> P" by simp |
1344 |
1353 |
1345 text {* |
1354 text {* |
1346 Here is how this rule can be used for rewriting: |
1355 Here is how this rule can be used for rewriting: |
1347 |
1356 |
1348 @{ML_response_fake "Conv.rewr_conv @{thm true_conj1} @{cterm \"True \<or> False\"}" |
1357 @{ML_response_fake [display,gray] |
1349 "True \<and> False \<equiv> False"} |
1358 "Conv.rewr_conv @{thm true_conj1} @{cterm \"True \<or> False\"}" |
1350 *} |
1359 "True \<and> False \<equiv> False"} |
1351 |
1360 *} |
1352 text {* |
1361 |
1353 Basic conversions can be combined with a number of conversionals, i.e. |
1362 text {* |
1354 conversion combinators: |
1363 Basic conversions can be combined with a number of conversionals, i.e. |
1355 |
1364 conversion combinators: |
1356 @{ML_response_fake |
1365 |
1357 "(Thm.beta_conversion true then_conv Conv.rewr_conv @{thm true_conj1}) |
1366 @{ML_response_fake [display,gray] |
|
1367 "(Thm.beta_conversion true then_conv Conv.rewr_conv @{thm true_conj1}) |
1358 @{cterm \"(\<lambda>x. x \<and> False) True\"}" |
1368 @{cterm \"(\<lambda>x. x \<and> False) True\"}" |
1359 "(\<lambda>x. x \<and> False) True \<equiv> False"} |
1369 "(\<lambda>x. x \<and> False) True \<equiv> False"} |
1360 |
1370 |
1361 @{ML_response_fake |
1371 @{ML_response_fake [display,gray] |
1362 "(Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv) |
1372 "(Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv) |
1363 @{cterm \"P \<or> (True \<and> Q)\"}" |
1373 @{cterm \"P \<or> (True \<and> Q)\"}" |
1364 "P \<or> (True \<and> Q) \<equiv> P \<or> (True \<and> Q)"} |
1374 "P \<or> (True \<and> Q) \<equiv> P \<or> (True \<and> Q)"} |
1365 |
1375 |
1366 @{ML_response_fake |
1376 @{ML_response_fake [display,gray] |
1367 "Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) |
1377 "Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) |
1368 @{cterm \"P \<or> (True \<and> Q)\"}" |
1378 @{cterm \"P \<or> (True \<and> Q)\"}" |
1369 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"} |
1379 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"} |
1370 |
1380 |
1371 \begin{readmore} |
1381 \begin{readmore} |
1372 See @{ML_file "Pure/conv.ML"} for more conversionals. Further basic conversions |
1382 See @{ML_file "Pure/conv.ML"} for more conversionals. Further basic conversions |
1373 can be found in, for example, @{ML_file "Pure/thm.ML"}, |
1383 can be found in, for example, @{ML_file "Pure/thm.ML"}, |
1374 @{ML_file "Pure/drule.ML"}, and @{ML_file "Pure/meta_simplifier.ML"}. |
1384 @{ML_file "Pure/drule.ML"}, and @{ML_file "Pure/meta_simplifier.ML"}. |
1375 \end{readmore} |
1385 \end{readmore} |
1376 |
1386 |
1377 Conversions are a thin layer on top of Isabelle's inference kernel, and may |
1387 We will demonstrate this feature in the following example. |
1378 be seen as a controllable, bare-bone version of Isabelle's simplifier. We |
1388 |
1379 will demonstrate this feature in the following example. |
1389 To begin with, let's assumes we want to simplify with the rewrite rule |
1380 |
1390 @{text true_conj1}. As a conversion, this may look as follows: |
1381 To begin with, let's assumes we want to simplify with the rewrite rule |
1391 *} |
1382 @{text true_conj1}. As a conversion, this may look as follows: |
1392 |
1383 *} |
1393 ML{*fun all_true1_conv ctxt ct = |
1384 |
|
1385 ML {*fun all_true1_conv ctxt ct = |
|
1386 (case Thm.term_of ct of |
1394 (case Thm.term_of ct of |
1387 @{term "op \<and>"} $ @{term True} $ _ => |
1395 @{term "op \<and>"} $ @{term True} $ _ => |
1388 (Conv.arg_conv (all_true1_conv ctxt) then_conv |
1396 (Conv.arg_conv (all_true1_conv ctxt) then_conv |
1389 Conv.rewr_conv @{thm true_conj1}) ct |
1397 Conv.rewr_conv @{thm true_conj1}) ct |
1390 | _ $ _ => Conv.combination_conv (all_true1_conv ctxt) |
1398 | _ $ _ => Conv.combination_conv (all_true1_conv ctxt) |
1391 (all_true1_conv ctxt) ct |
1399 (all_true1_conv ctxt) ct |
1392 | Abs _ => Conv.abs_conv (fn (_, cx) => all_true1_conv cx) ctxt ct |
1400 | Abs _ => Conv.abs_conv (fn (_, cx) => all_true1_conv cx) ctxt ct |
1393 | _ => Conv.all_conv ct)*} |
1401 | _ => Conv.all_conv ct)*} |
1394 |
1402 |
1395 text {* |
1403 text {* |
1396 Here is this conversion in action: |
1404 Here is this conversion in action: |
1397 |
1405 |
1398 @{ML_response_fake |
1406 @{ML_response_fake [display,gray] |
1399 "all_true1_conv @{context} |
1407 "all_true1_conv @{context} |
1400 @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}" |
1408 @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}" |
1401 "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"} |
1409 "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"} |
1402 |
1410 |
1403 Now, let's complicate the task a bit: Rewrite according to the rule |
1411 Now, let make the task a bit more complicated by rewrite according to the rule |
1404 @{text true_conj1}, but only in the first arguments of @{term If}: |
1412 @{text true_conj1}, but only in the first arguments of @{term If}: |
1405 *} |
1413 *} |
1406 |
1414 |
1407 ML {*fun if_true1_conv ctxt ct = |
1415 ML{*fun if_true1_conv ctxt ct = |
1408 (case Thm.term_of ct of |
1416 (case Thm.term_of ct of |
1409 Const (@{const_name If}, _) $ _ => |
1417 Const (@{const_name If}, _) $ _ => |
1410 Conv.arg_conv (all_true1_conv ctxt) ct |
1418 Conv.arg_conv (all_true1_conv ctxt) ct |
1411 | _ $ _ => Conv.combination_conv (if_true1_conv ctxt) |
1419 | _ $ _ => Conv.combination_conv (if_true1_conv ctxt) |
1412 (if_true1_conv ctxt) ct |
1420 (if_true1_conv ctxt) ct |
1413 | Abs _ => Conv.abs_conv (fn (_, cx) => if_true1_conv cx) ctxt ct |
1421 | Abs _ => Conv.abs_conv (fn (_, cx) => if_true1_conv cx) ctxt ct |
1414 | _ => Conv.all_conv ct)*} |
1422 | _ => Conv.all_conv ct)*} |
1415 |
1423 |
1416 text {* |
1424 text {* |
1417 Here is an application of this conversion: |
1425 Here is an application of this conversion: |
1418 |
1426 |
1419 @{ML_response_fake |
1427 @{ML_response_fake [display,gray] |
1420 "if_true1_conv @{context} |
1428 "if_true1_conv @{context} |
1421 @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}" |
1429 @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}" |
1422 "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"} |
1430 "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"} |
1423 *} |
1431 *} |
1424 |
1432 |
1425 text {* |
1433 text {* |
1426 Conversions can also be turned into a tactic with the @{ML CONVERSION} |
1434 Conversions can also be turned into a tactic with the @{ML CONVERSION} |
1427 tactical, and there are predefined conversionals to traverse a goal state. |
1435 tactical, and there are predefined conversionals to traverse a goal state. |
1428 Given a state @{term "\<And>x. P \<Longrightarrow> Q"}, the conversional |
1436 Given a state @{term "\<And>x. P \<Longrightarrow> Q"}, the conversional |
1429 @{ML Conv.params_conv} applies a conversion to @{term "P \<Longrightarrow> Q"}; |
1437 @{ML Conv.params_conv} applies a conversion to @{term "P \<Longrightarrow> Q"}; |
1430 given a state @{term "\<lbrakk> P1; P2 \<rbrakk> \<Longrightarrow> Q"}, |
1438 given a state @{term "\<lbrakk> P1; P2 \<rbrakk> \<Longrightarrow> Q"}, |
1431 the conversional @{ML Conv.prems_conv} applies a conversion to the premises |
1439 the conversional @{ML Conv.prems_conv} applies a conversion to the premises |
1432 @{term P1} and @{term P2}, and @{ML Conv.concl_conv} applies a conversion to |
1440 @{term P1} and @{term P2}, and @{ML Conv.concl_conv} applies a conversion to |
1433 the conclusion @{term Q}. |
1441 the conclusion @{term Q}. |
1434 |
1442 |
1435 Assume we want to apply @{ML all_true1_conv} only in the conclusion |
1443 Assume we want to apply @{ML all_true1_conv} only in the conclusion |
1436 of the goal, and @{ML if_true1_conv} should only be applied in the premises. |
1444 of the goal, and @{ML if_true1_conv} should only be applied in the premises. |
1437 Here is a tactic doing exactly that: |
1445 Here is a tactic doing exactly that: |
1438 *} |
1446 *} |
1439 |
1447 |
1440 ML {*val true1_tac = CSUBGOAL (fn (goal, i) => |
1448 ML{*val true1_tac = CSUBGOAL (fn (goal, i) => |
1441 let val ctxt = ProofContext.init (Thm.theory_of_cterm goal) |
1449 let val ctxt = ProofContext.init (Thm.theory_of_cterm goal) |
1442 in |
1450 in |
1443 CONVERSION ( |
1451 CONVERSION ( |
1444 Conv.params_conv ~1 (fn cx => |
1452 Conv.params_conv ~1 (fn cx => |
1445 (Conv.prems_conv ~1 (if_true1_conv cx)) then_conv |
1453 (Conv.prems_conv ~1 (if_true1_conv cx)) then_conv |
1446 Conv.concl_conv ~1 (all_true1_conv cx)) ctxt) i |
1454 Conv.concl_conv ~1 (all_true1_conv cx)) ctxt) i |
1447 end)*} |
1455 end)*} |
1448 |
1456 |
1449 text {* |
1457 text {* |
1450 To demonstrate this tactic, consider the following example: |
1458 To demonstrate this tactic, consider the following example: |
1451 *} |
1459 *} |
1452 |
1460 |
1453 lemma |
1461 lemma |
1454 "if True \<and> P then P else True \<and> False \<Longrightarrow> |
1462 "if True \<and> P then P else True \<and> False \<Longrightarrow> |
1455 (if True \<and> Q then Q else P) \<longrightarrow> True \<and> (True \<and> Q)" |
1463 (if True \<and> Q then Q else P) \<longrightarrow> True \<and> (True \<and> Q)" |