1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
|
\chapter{Introduction to Proof with HOL}
\label{proof}
For a logician, a formal proof is a sequence, each of whose elements is
either an {\it axiom\/} or follows from earlier members of the sequence by a
{\it rule of inference\/}. A theorem is the last element of a proof.
Theorems are represented in \HOL\ by values of an abstract
type\footnote{Abstract types are explained in \DESCRIPTION.}
{\small\verb%thm%}. The only way to create theorems is by generating a
proof. In \HOL\ (following \LCF), this consists in applying \ML\ functions
representing {\it rules of inference\/} to axioms or previously generated
theorems. The sequence of such applications directly corresponds to a
logician's proof.
There are five axioms of the \HOL\ logic and eight primitive
inference rules. The axioms are bound to ML names. For example, the Law of
Excluded Middle is bound to the \ML\ name {\small\verb%BOOL_CASES_AX%}:
\begin{session}
\begin{verbatim}
#BOOL_CASES_AX;;
|- !t. (t = T) \/ (t = F)
\end{verbatim}
\end{session}
Theorems are printed with a preceding turnstile {\small\verb%|-%} as
illustrated above; the symbol `{\small\verb%!%}' is the universal
quantifier `$\forall$'. Rules of inference are \ML\ functions that
return values of type {\small\verb%thm%}.
An example of a rule of inference is {\it
specialization\/} (or $\forall$-elimination).
In standard `natural deduction'
notation this is:
\[ \Gamma\turn \uquant{x}t\over \Gamma\turn t[t'/x]\]
\begin{itemize}
\item $t[t'/x]$ denotes the result of substituting $t'$ for free
occurrences of $x$ in $t$, with the restriction that no free variables in $t'$
become bound after substitution.
\end{itemize}
\noindent This rule is represented in \ML\
by a function
{\small\verb%SPEC%},\footnote{{\tt SPEC} is not a
primitive rule of inference in the HOL logic, but is a derived rule. Derived rules
are described in Section~\ref{forward}.}
which takes as arguments a term
{\small\verb%"%}$a${\small\verb%"%} and a theorem
{\small\verb%|- !%}$x${\small\verb%.%}$t[x]$ and returns the theorem
{\small\verb%|- %}$t[a]$, the result of substituting $a$ for $x$ in $t[x]$.
\setcounter{sessioncount}{1}
\begin{session}
\begin{verbatim}
#let Th1 = BOOL_CASES_AX;;
Th1 = |- !t. (t = T) \/ (t = F)
#let Th2 = SPEC "1 = 2" Th1;;
Th2 = |- ((1 = 2) = T) \/ ((1 = 2) = F)
\end{verbatim}
\end{session}
This session consists of a proof of two steps: using an axiom and
applying the rule \ml{SPEC}; it interactively performs the following proof:
\begin{enumerate}
\item $\turn \uquant{t} t=\top\ \disj\ t=\bot$ \hfill
[Axiom \ml{BOOL\_CASES\_AX}]
\item $\turn (1{=}2)=\top\ \disj\ (1{=}2)=\bot$\hfill [Specializing line 1 to `$1{=}2$']
\end{enumerate}
If the argument to an \ML\ function representing a rule of inference is of the
wrong kind, or violates a condition of the rule, then the application fails.
For example, $\ml{SPEC}\ t\ th$ will fail if $th$ is not of the form
$\ml{|-\ !}x\ml{.}\cdots$
or if it is of this form but the type of $t$ is not the same
as the type of $x$, or if the free variable restriction is not met.
\begin{session}
\begin{verbatim}
#SPEC "1=2" Th2;;
evaluation failed SPEC
#SPEC "1" Th1;;
evaluation failed SPEC
\end{verbatim}
\end{session}
\noindent As this session illustrates, the failure token does not always
indicate the exact reason for failure. The failure conditions for rules of
inference are given in \REFERENCE.
A proof in the \HOL\ system is constructed by repeatedly applying inference
rules to axioms or to previously proved theorems.
Since proofs may consist of millions of steps, it is necessary to provide
tools to make proof construction easier for the user. The proof generating
tools in the \HOL\ system are just those of \LCF, and are described later.
The general form of a theorem is $t_1,\ldots,t_n\ $\ml{|-}$\ t$, where $t_1$,
$\ldots$ , $t_n$ are boolean terms called the {\it assumptions} and $t$ is a
boolean term called the {\it conclusion\/}. Such a theorem asserts that if its
assumptions are true then so is its conclusion. Its truth conditions are thus
the same as those for the single term
$(t_1${\small\verb%/\%}$\ldots${\small\verb%/\%}$t_n$)\ml{==>}$t$.
Theorems with no assumptions are printed
out in the form \ml{|-}$\ t$.
The five axioms and eight primitive inference rules of the \HOL\ logic are
described in detail in the document \DESCRIPTION. Every
value of type \ml{thm} in the \HOL\ system can be obtained by repeatedly
applying primitive inference rules to axioms. When the \HOL\ system is built,
the eight primitive rules of inference are defined and the five axioms are
bound to their \ML\ names, all other predefined theorems are proved using rules
of inference as the system is made.\footnote{This is a slight
over-simplification.} This is one of the reasons why making \ml{hol} takes so
long.
In the rest of this chapter, the process of {\it forward proof\/}, which has
just been sketched, is described in more detail. In Chapter~\ref{tactics} {\it
goal directed proof\/} is described, including the important notions of {\it
tactics\/} and {\it tacticals\/}, due to Robin Milner.
\section{Forward proof}
\label{forward}
Three of the primitive inference rules of the
\HOL\ logic are \ml{ASSUME} (assumption introduction),
\ml{DISCH} (discharging or assumption elimination) and \ml{MP} (Modus Ponens).
These rules will be used to illustrate forward proof and the writing of derived
rules.
The inference rule {\small\verb%ASSUME%} generates theorems of the form
$t${\small\verb% |- %}$t$. Note, however, that the \ML\ printer prints each
assumption as a dot (but this default can be changed; see below). The function
{\small\verb%dest_thm%} decomposes a theorem into a pair consisting of list of
assumptions and the conclusion. The \ML\ type \ml{goal} abbreviates
{\small\verb%(term)list # term%}, this is motivated in Section~\ref{tactics}.
\begin{session}
\begin{verbatim}
#let Th3 = ASSUME "t1==>t2";;
Th3 = . |- t1 ==> t2
#dest_thm Th3;;
["t1 ==> t2"],"t1 ==> t2" : goal
\end{verbatim}
\end{session}
A sort of dual to \ml{ASSUME} is the primitive inference rule
\ml{DISCH} (discharging, assumption elimination) which infers from
a theorem of the form $\cdots t_1\cdots\ml{\ |-\ }t_2$ the new theorem
$\cdots\ \cdots\ \ml{|-}\ t_1\ml{==>}t_2$. \ml{DISCH} takes as arguments
the term to be discharged (\ie\ $t_1$) and the theorem from whose
assumptions it is to be discharged and returns the result of the discharging.
The following session illustrates this; it also illustrates what happens when
\ml{=>}, which is part of the syntax of conditional terms
(see the table on page~\pageref{logic-table}),
is erroneously typed instead of the implication symbol \ml{==>}.
\begin{session}
\begin{verbatim}
#let Th4 = DISCH "t1=>t2" Th3;;
need 2 nd branch to conditional
skipping: t2 " Th3 ;; parse failed
#let Th4 = DISCH "t1==>t2" Th3;;
Th4 = |- (t1 ==> t2) ==> t1 ==> t2
\end{verbatim}
\end{session}
\noindent Note that the term being discharged need not be in the assumptions; in
this case they will be unchanged.
\begin{session}\begin{verbatim}
#DISCH "1=2" Th3;;
. |- (1 = 2) ==> t1 ==> t2
#dest_thm it;;
(["t1 ==> t2"], "(1 = 2) ==> t1 ==> t2") : goal
\end{verbatim}\end{session}
In \HOL\, the rule \ml{MP} of Modus Ponens is specified in conventional
notation by:
\[ \Gamma_1 \turn t_1 \imp t_2 \qquad\qquad \Gamma_2\turn t_1\over
\Gamma_1 \cup \Gamma_2 \turn t_2\]
\noindent The \ML\ function \ml{MP} takes argument theorems of the
form \ml{$\cdots\ $|-$\ t_1$\ ==>\ $t_2$} and \ml{$\cdots\ $|-$\ t_1$}
and returns \ml{$\cdots\ $|-$\ t_2$}. The next session illustrates the use of
\ml{MP} and also a common error, namely not supplying the \HOL\ logic type
checker with enough information.
\begin{session}\begin{verbatim}
#let Th5 = ASSUME "t1";;
Indeterminate types: "t1:?"
evaluation failed types indeterminate in quotation
#let Th5 = ASSUME "t1:bool";;
Th5 = . |- t1
#let Th6 = MP Th3 Th5;;
Th6 = .. |- t2
\end{verbatim}\end{session}
The hypotheses of \ml{Th6} can be inspected with the \ML\ function \ml{hyp},
which returns the list of assumptions of a theorem (the conclusion is returned by
\ml{concl}).
\begin{session}\begin{verbatim}
#hyp Th6;;
["t1 ==> t2"; "t1"] : term list
\end{verbatim}\end{session}
\HOL\ can be made to print out hypotheses of theorems explicitly by
telling \ML\ to use the function \ml{print\_all\_thm} instead of
the default \ml{print\_thm}.
\begin{session}\begin{verbatim}
#top_print print_all_thm;;
- : (thm -> void)
#Th5;;
t1 |- t1
#Th6;;
t1 ==> t2, t1 |- t2
\end{verbatim}\end{session}
\noindent Discharging \ml{Th6} twice establishes the theorem
\ml{|-\ t1 ==> (t1==>t2) ==> t2}.
\begin{session}\begin{verbatim}
#let Th7 = DISCH "t1==>t2" Th6;;
Th7 = t1 |- (t1 ==> t2) ==> t2
#let Th8 = DISCH "t1:bool" Th7;;
Th8 = |- t1 ==> (t1 ==> t2) ==> t2
\end{verbatim}\end{session}
The sequence of theorems: \ml{Th3},
\ml{Th5}, \ml{Th6}, \ml{Th7}, \ml{Th8} constitutes a proof in \HOL\ of
the theorem \ml{|-\ t1 ==> (t1 ==> t2) ==> t2}. In stardard logical notation this
proof could be written:
\begin{enumerate}
\item $ t_1\imp t_2\turn t_1\imp t_2$ \hfill
[Assumption introduction]
\item $ t_1\turn t_1$ \hfill
[Assumption introduction]
\item $t_1\imp t_2,\ t_1 \turn t_2 $ \hfill
[Modus Ponens applied to lines 1 and 2]
\item $t_1 \turn (t_1\imp t_2)\imp t_2$ \hfill
[Discharging the first assumption of line 3]
\item $\turn t_1 \imp (t_1 \imp t_2) \imp t_2$ \hfill
[Discharging the only assumption of line 4]
\end{enumerate}
\subsection{Derived rules}
A {\it proof from hypothesis $th_1, \ldots, th_n$} is a sequence each of whose
elements is either an axiom, or one of the hypotheses $th_i$, or follows from
earlier elements by a rule of inference.
For example, a proof of $\Gamma,\ t'\turn t$ from the hypothesis
$\Gamma\turn t$ is:
\begin{enumerate}
\item $t'\turn t'$ \hfill [Assumption introduction]
\item $\Gamma\turn t$ \hfill [Hypothesis]
\item $\Gamma\turn t'\imp t$ \hfill [Discharge $t'$ from line 2]
\item $\Gamma,\ t'\turn t$ \hfill [Modus Ponens applied to lines 3 and 1]
\end{enumerate}
\noindent This proof works for any hypothesis of the form $\Gamma\turn t$
and any boolean term $t'$ and
shows that the result of adding an arbitrary hypothesis to a theorem is another
theorem (because the four lines above can be added to any proof of
$\Gamma\turn t$ to get a proof of $\Gamma,\ t'\turn t$).\footnote{This property
of the logic is called {\it monotonicity}.} For example,
the next session uses this proof to add the hypothesis \ml{"t3"} to
\ml{Th6}.
\begin{session}\begin{verbatim}
#let Th9 = ASSUME "t3:bool";;
Th9 = t3 |- t3
#let Th10 = DISCH "t3:bool" Th6;;
Th10 = t1 ==> t2, t1 |- t3 ==> t2
#let Th11 = MP Th10 Th9;;
Th11 = t1 ==> t2, t1, t3 |- t2
\end{verbatim}\end{session}
A {\it derived rule\/} is an \ML\ procedure that generates a proof from given hypotheses
each time it is invoked. The hypotheses are the arguments of the rule.
To illustrate this, a rule, called \ml{ADD\_ASSUM}, will now
be defined as an \ML\ procedure that carries
out the proof above. In standard notation this would be described by:
\[ \Gamma\turn t\over \Gamma,\ t'\turn t \]
\noindent The \ML\ definition is:
\begin{session}\begin{verbatim}
#let ADD_ASSUM t th =
# let th9 = ASSUME t
# in
# let th10 = DISCH t th
# in
# MP th10 th9;;
ADD_ASSUM = - : (term -> thm -> thm)
#ADD_ASSUM "t3:bool" Th6;;
t1 ==> t2, t1, t3 |- t2
\end{verbatim}\end{session}
\noindent The body of \ml{ADD\_ASSUM} has been coded to mirror the proof done
in session~10 above, so as to show how an interactive proof can be generalized
into a procedure. But \ml{ADD\_ASSUM} can be written much more
concisely as:
\begin{session}\begin{verbatim}
#let ADD_ASSUM t th = MP (DISCH t th) (ASSUME t);;
ADD_ASSUM = - : (term -> thm -> thm)
#ADD_ASSUM t3 Th6;;
t1 ==> t2, t1, t3 |- t2
\end{verbatim}\end{session}
Another example of a derived inference rule is \ml{UNDISCH}; this moves the
antecedent of an implication to the assumptions.
\[ \Gamma\turn t_1\imp t_2 \over\Gamma,\ t_1\turn t_2 \]
\noindent An \ML\ derived rule that implements this is:
\begin{session}\begin{verbatim}
#let UNDISCH th =
# MP th (ASSUME(fst(dest_imp(concl th))));;
UNDISCH = - : (thm -> thm)
#Th10;;
t1 ==> t2, t1 |- t3 ==> t2
#UNDISCH Th10;;
t1 ==> t2, t1, t3 |- t2
#it = Th11;;
true : bool
\end{verbatim}\end{session}
\noindent Each time \ml{UNDISCH\ $\Gamma\turn t_1\imp t_2$} is executed,
the following proof is performed:
\begin{enumerate}
\item $t_1\turn t_1$ \hfill [Assumption introduction]
\item $\Gamma\turn t_1\imp t_2$ \hfill [Hypothesis]
\item $\Gamma,\ t_1\turn t_2$ \hfill [Modus Ponens applied to lines 2 and 1]
\end{enumerate}
The rules \ml{ADD\_ASSUM} and \ml{UNDISCH} are the first derived rules
defined when the \HOL\ system is built. For a description
of the main rules see the section on derived rules in
\DESCRIPTION.
\section{Rewriting}
An important derived rule is \ml{REWRITE\_RULE}. This takes a list of
conjunctions of equations, \ie\ a list of theorems of the form:
\[ \Gamma\turn (u_1 = v_1) \conj (u_2 = v_2) \conj \ldots\ \conj (u_n = v_n)\]
\noindent and a theorem
$\Delta\turn t$ and repeatedly replaces instances of $u_i$ in $t$ by the
corresponding instance of $v_i$ until no further change occurs. The result is
a theorem $\Gamma\cup\Delta\turn t'$ where $t'$ is the result of rewriting $t$
in this way. The session below illustrates the use of \ml{REWRITE\_RULE}. In
it the list of equations is a list \ml{rewrite\_list} containing the pre-proved
theorems \ml{ADD\_CLAUSES} and \ml{MULT\_CLAUSES}. These theorems {\it
autoload\/} from the theory \ml{arithmetic}. This means that the first time
they are mentioned in a session, which is when \ml{rewrite\_list} is defined,
they are automatically fetched and bound to their \ML\ name.
\begin{session}\begin{verbatim}
#let rewrite_list = [ADD_CLAUSES;MULT_CLAUSES];;
Theorem MULT_CLAUSES autoloaded from theory `arithmetic`.
MULT_CLAUSES =
|- !m n.
(0 * m = 0) /\
(m * 0 = 0) /\
(1 * m = m) /\
(m * 1 = m) /\
((SUC m) * n = (m * n) + n) /\
(m * (SUC n) = m + (m * n))
Theorem ADD_CLAUSES autoloaded from theory `arithmetic`.
ADD_CLAUSES =
|- (0 + m = m) /\
(m + 0 = m) /\
((SUC m) + n = SUC(m + n)) /\
(m + (SUC n) = SUC(m + n))
rewrite_list =
[|- (0 + m = m) /\
(m + 0 = m) /\
((SUC m) + n = SUC(m + n)) /\
(m + (SUC n) = SUC(m + n));
|- !m n.
(0 * m = 0) /\
(m * 0 = 0) /\
(1 * m = m) /\
(m * 1 = m) /\
((SUC m) * n = (m * n) + n) /\
(m * (SUC n) = m + (m * n))]
: thm list
\end{verbatim}\end{session}
\begin{session}\begin{verbatim}
#REWRITE_RULE rewrite_list (ASSUME "(m+0)<(1*n)+(SUC 0)");;
(m + 0) < ((1 * n) + (SUC 0)) |- m < (SUC n)
\end{verbatim}\end{session}
\noindent This can then be rewritten using a pre-proved theorem \ml{LESS\_THM}:
\begin{session}\begin{verbatim}
REWRITE_RULE [LESS_THM] it;;
Theorem LESS_THM autoloaded from theory `prim_rec`.
LESS_THM = |- !m n. m < (SUC n) = (m = n) \/ m < n
(m + 0) < ((1 * n) + (SUC 0)) |- (m = n) \/ m < n
\end{verbatim}\end{session}
\ml{REWRITE\_RULE} is not a primitive in \HOL, but is a derived rule. It is
inherited from Cambridge \LCF\ and was implemented by Larry Paulson (see
his paper \cite{lcp_rewrite} for details). In addition to the supplied equations,
\ml{REWRITE\_RULE} has some built in standard simplifications:
\begin{session}\begin{verbatim}
#REWRITE_RULE [] (ASSUME "(T /\ x) \/ F ==> F");;
T /\ x \/ F ==> F |- ~x
\end{verbatim}\end{session}
\noindent The complete list of these built-in rewrites is
held in the \ML\ variable \ml{basic\_rewrites}:
\newpage % PBHACK
\begin{session}\begin{verbatim}
#basic_rewrites;;
[|- !x. (x = x) = T;
|- !t.
((T = t) = t) /\ ((t = T) = t) /\ ((F = t) = ~t) /\ ((t = F) = ~t);
|- (!t. ~~t = t) /\ (~T = F) /\ (~F = T);
|- !t.
(T /\ t = t) /\
(t /\ T = t) /\
(F /\ t = F) /\
(t /\ F = F) /\
(t /\ t = t);
|- !t.
(T \/ t = T) /\
(t \/ T = T) /\
(F \/ t = t) /\
(t \/ F = t) /\
(t \/ t = t);
|- !t.
(T ==> t = t) /\
(t ==> T = T) /\
(F ==> t = T) /\
(t ==> t = T) /\
(t ==> F = ~t);
|- !t1 t2. ((T => t1 | t2) = t1) /\ ((F => t1 | t2) = t2);
|- !t1 t2. t1 <=> t2 = (t1 = t2);
|- !t. (!x. t) = t;
|- !t. (?x. t) = t;
|- !t1 t2. (\x. t1)t2 = t1;
|- !x. FST x,SND x = x;
|- !x y. FST(x,y) = x;
|- !x y. SND(x,y) = y]
: thm list
\end{verbatim}\end{session}
There are elaborate facilities in \HOL\ for producing customized rewriting tools
which scan through terms in user programmed orders; \ml{REWRITE\_RULE} is the tip
of an iceberg, see \DESCRIPTION\ for more details.
\section{Tautologies}
ICL Defence Systems have supplied a tautology checker as a library program.
This takes any term \ml{"$t$"} and returns \ml{|-~$t$} if $t$ is an instance
of a tautology of the propositional calculus.
This checker is a derived rule and constructs (behind the scenes) a proof
of any tautology. It is in the library \ml{taut} which is loaded with
the function \ml{load\_library}.
\begin{session}\begin{verbatim}
#load_library `taut`;;
Loading library `taut` ...
evaluation failed load -- foo/Library/taut/taut ml file not found
\end{verbatim}\end{session}
\noindent This error message shows that \HOL\ has not been installed
properly; see Chapter~\ref{install}. The \ml{hol} being used for this
session is on the directory {\small\verb%/tmp_mnt/home/flint/mjcg/hol%},
but:
\begin{session}\begin{verbatim}
#HOLdir;;
`wonk/foo/mumble` : string
\end{verbatim}\end{session}
\noindent which shows that \HOL\ thinks it is living on
{\small\verb%wonk/foo/mumble%}. This is easy to fix:
\begin{session}\begin{verbatim}
#install `/tmp_mnt/home/flint/mjcg/hol`;;
() : void
HOLdir = `/tmp_mnt/home/flint/mjcg/hol` : string
\end{verbatim}\end{session}
\noindent Now the library \ml{taut} will load properly.
\begin{session}\begin{verbatim}
#load_library `taut`;;
Loading library `taut` ...
[fasl /tmp_mnt/home/flint/mjcg/hol/Library/taut/taut_ml.o]
.......................
Library `taut` loaded.
() : void
\end{verbatim}\end{session}
The following session illustrates \ml{TAUT\_RULE}, which is one of the functions
loaded when the library \ml{taut} is loaded.
\begin{session}\begin{verbatim}
#TAUT_RULE "((A ==> B) ==> A) ==> A";;
|- ((A ==> B) ==> A) ==> A
#TAUT_RULE "((A ==> B) ==> A) ==> B";;
evaluation failed TAC_PROOF -- TAUT_TAC - term not a tautology
\end{verbatim}\end{session}
\noindent \ml{TAUT\_RULE} has \ML\ type {\small\verb%term -> thm%} which
is abbreviated to \ml{conv} by \ML\ (the motivation for this name is
discussed in the section on conversions in \DESCRIPTION).
\begin{session}\begin{verbatim}
#TAUT_RULE;;
- : conv
\end{verbatim}\end{session}
\noindent Such type abbreviations are discussed in the next chapter.
\chapter{Goal Oriented Proof: Tactics and Tacticals}
\label{backward}\label{tactics}
The style of forward proof described in the previous chapter is unnatural and
too `low level' for many applications. An important advance in proof generating
methodology was made by Robin Milner in the early 1970s when he invented the
notion of {\it tactics\/}. A tactic is a function that does two things.
\begin{myenumerate}
\item Splits a `goal' into `subgoals'.
\item Keeps track of the reason why solving the subgoals will solve the goal.
\end{myenumerate}
\noindent Consider, for example, the rule of $\wedge$-introduction\footnote{In
higher order logic this is a derived rule; in first order logic it is usually
primitive. In HOL the rule is called {\tt CONJ} and its derivation is given in
\DESCRIPTION.} shown below:
\[ \Gamma_1\turn
t_1\qquad\qquad\qquad\Gamma_2\turn t_2\over \Gamma_1\cup\Gamma_2 \turn t_1\conj
t_2 \]
\noindent In \HOL, $\wedge$-introduction is represented by the \ML\ function
\ml{CONJ}:
\[\ml{CONJ}\ (\Gamma_1\turn t_1)\ (\Gamma_2\turn t_2) \ \ \leadsto\
\ (\Gamma_1\cup\Gamma_2\turn t_1\conj t_2)\]
\noindent This is illustrated in the
following new session (note that the session number has been reset to
{\small\sl 1}):
\setcounter{sessioncount}{1}
\begin{session}\begin{verbatim}
#top_print print_all_thm;;
- : (thm -> void)
#let Th1 = ASSUME "A:bool" and Th2 = ASSUME "B:bool";;
Th1 = A |- A
Th2 = B |- B
#let Th3 = CONJ Th1 Th2;;
Th3 = A, B |- A /\ B
\end{verbatim}\end{session}
Suppose the goal is to prove $A\conj B$, then this rule says
that it is sufficient
to prove the two subgoals $A$ and $B$, because from $\turn A$ and $\turn B$
the theorem $\turn A\conj B$ can be deduced. Thus:
\begin{myenumerate}
\item To prove $\turn A \conj B$ it is sufficient to
prove $\turn A$ and $\turn B$.
\item The justification for the reduction of the
goal $\turn A \conj B$ to the two subgoals $\turn A$
and $\turn B$ is the rule of $\wedge$-introduction.
\end{myenumerate}
A {\it goal\/} in \HOL\ is a pair
\ml{([$t_1$;\ldots;$t_n$],$t$)} of \ML\ type
{\small\verb%term list # term%}. An {\it achievement\/} of such a goal
is a theorem
\ml{$t_1$,$\ldots$,$t_n$\ |-\ $t$}.
A tactic is an \ML\ function that when applied to a goal generates subgoals
together with a {\it justification function\/} or {\it validation\/},
which will be an \ML\ derived inference
rule, that can be used to infer an achievement of the original goal from
achievements
of the subgoals.
{\bf Aside:} \ML\ has a type abbreviating mechanism which is used to give mnemonic
names to the various types associated with goal oriented proof. Type abbreviations
can be seen by evaluating \ml{print\_defined\_types()}:
\begin{session}\begin{verbatim}
#print_defined_types();;
proof = (thm list -> thm)
goal = (term list # term)
tactic = ((term list # term) -> subgoals)
thm_tactic = (thm -> tactic)
thm_tactical = ((thm -> tactic) -> thm_tactic)
conv = (term -> thm)
term_net -- an abstract type
subgoals = ((term list # term) list # proof)
goalstack -- an abstract type
\end{verbatim}\end{session}
\noindent The left hand side of these abbreviations can be used anywhere that the
right hand side can (abstract types are explained elsewhere). The default is that
the printer will print out abbreviations at top-level, but this behaviour can
be changed (see the flag \ml{print\_lettypes} in \DESCRIPTION).
{\bf End aside.}
If $T$ is a tactic (\ie\ an \ML\ function of type \ml{tactic}) and $g$
is a goal (\ie\ an \ML\ function of type \ml{goal}), then
applying $T$ to $g$ (\ie\ evaluating the \ML\
expression $T\ g$) will result in
an object of \ML\ type {\small\verb%subgoals%}, \ie\ a pair whose
first component is a list of
goals and whose second component is a justification function, \ie\ has
\ML\ type {\small\verb%proof%}.
An example tactic is \ml{CONJ\_TAC} which implements (i) and (ii) above.
For example, consider the utterly trivial goal of showing {\small\verb%T /\ T%},
where \ml{T} is a constant that stands for $true$:
\begin{session}\begin{verbatim}
#let goal1 =([], "T /\ T");;
goal1 = ([], "T /\ T") : (* list # term)
#CONJ_TAC goal1;;
([([], "T"); ([], "T")], -) : subgoals
#let goal_list,just_fn = it;;
goal_list = [([], "T"); ([], "T")] : goal list
just_fn = - : proof
\end{verbatim}\end{session}
\noindent \ml{CONJ\_TAC} has produced a goal list consisting of two identical
subgoals of just showing \ml{([],"T")}. Now, there is a preproved theorem in
\HOL, called \ml{TRUTH}, that achieves this goal:
\begin{session}\begin{verbatim}
#TRUTH;;
|- T
\end{verbatim}\end{session}
\noindent Applying the justification function \ml{just\_fn} to a list
of theorems achieving the goals in \ml{goal\_list} results
in a theorem achieving the original goal:
\begin{session}\begin{verbatim}
#just_fn [TRUTH;TRUTH];;
|- T /\ T
\end{verbatim}\end{session}
Although this example is trivial, it does illustrate the essential idea of
tactics. Note that tactics are not special theorem-proving primitives; they
are just \ML\ functions. For example, the definition of \ml{CONJ\_TAC} is
simply:
\begin{hol}\begin{verbatim}
let CONJ_TAC (asl,w) =
let l,r = dest_conj w
in
([(asl,l); (asl,r)], \[th1;th2]. CONJ th1 th2)
\end{verbatim}\end{hol}
\noindent The \ML\ function \ml{dest\_conj} splits a conjunction into its
two conjuncts:
If \ml{(asl,"$t_1$}{\small\verb%/\%}\ml{$t_2$")}
is a goal, then \ml{CONJ\_TAC} splits
it into the list of two subgoals \ml{(asl,$t_1$)} and
\ml{(asl,$t_2$)}. The justification function,
{\small\verb%\[th1;th2]. CONJ th1 th2%}
takes
a list \ml{[$th_1$;$th_2$]} of theorems and applies the rule \ml{CONJ}
to $th_1$ and $th_2$.
To summarize:
if $T$ is a tactic and $g$
is a goal, then
applying $T$ to $g$ will result in
an object of \ML\ type {\small\verb%subgoals%}, \ie\ a pair whose
first component is a list of
goals and whose second component is a justification function, \ie\ has
\ML\ type {\small\verb%proof%}.
Suppose $T\ g${\small\verb% = ([%}$g_1${\small\verb%;%}$\ldots${\small\verb%;%}$g_n${\small\verb%],%}$p${\small\verb%)%}.
The idea is that $g_1$ , $\ldots$ , $g_n$ are subgoals and $p$
is a `justification' of the reduction of goal $g$ to subgoals
$g_1$ , $\ldots$ , $g_n$.
Suppose further that the subgoals $g_1$ , $\ldots$ , $g_n$ have been solved.
This would mean that
theorems $th_1$ , $\ldots$ , $th_n$ had been proved
such that each $th_i$ ($1\leq i\leq n$) `achieves' the goal $g_i$.
The justification $p$ (produced
by applying $T$ to $g$) is an \ML\
function which when applied to the list
{\small\verb%[%}$th_1${\small\verb%;%}$\ldots${\small\verb%;%}$th_n${\small\verb%]%} returns a theorem, $th$,
which `achieves' the original goal $g$.
Thus $p$ is a function for converting a solution of the subgoals to a
solution of the original goal. If $p$
does this successfully, then the tactic $T$ is
called {\it valid\/}.
Invalid tactics cannot result in the proof of invalid theorems;
the worst they can do is result in insolvable goals or unintended theorems
being proved.
If $T$ were invalid and were used
to reduce goal $g$ to subgoals $g_1$ , $\ldots$ , $g_n$,
then effort might be spent proving
theorems $th_1$ , $\ldots$ , $th_n$ to
achieve the subgoals $g_1$ , $\ldots$ , $g_n$,
only to find out after the work is done that this is a blind alley
because $p${\small\verb%[%}$th_1${\small\verb%;%}$\ldots${\small\verb%;%}$th_n${\small\verb%]%}
doesn't achieve $g$ (\ie\ it fails,
or else it achieves some other goal).
A theorem {\it achieves\/} a goal if the assumptions of the theorem are
included in the assumptions of the goal {\it and\/} if the conclusion of the
theorems is equal (up to the renaming of bound variables) to the conclusion of
the goal. More precisely, a theorem
\begin{center}
$t_1$, $\dots$, $t_m${\small\verb% |- %}$t$
\end{center}
\noindent achieves a goal
\begin{center}
{\small\verb%([%}$u_1${\small\verb%;%}$\ldots${\small\verb%;%}$u_n${\small\verb%],%}$u${\small\verb%)%}
\end{center}
\noindent if and only if $\{t_1,\ldots,t_m\}$
is a subset of $\{u_1,\ldots,u_n\}$ and $t$ is equal to $u$ (up
to renaming of bound variables). For example, the goal
{\small\verb%(["x=y";"y=z";"z=w"],"x=z")%} is achieved by the theorem
{\small\verb%x=y, y=z |- x=z%} (the assumption {\small\verb%"z=w"%} is not
needed).
A tactic {\it solves\/} a goal if it reduces the goal
to the empty list
of subgoals. Thus $T$ solves $g$ if $T\ g${\small\verb% = ([],%}$p${\small\verb%)%}.
If this is the case and if $T$ is valid, then $p${\small\verb%[]%}
will evaluate to a theorem achieving $g$.
Thus if $T$ solves $g$ then the \ML\ expression
{\small\verb%snd(%}$T\ g${\small\verb%)[]%} evaluates to
a theorem achieving $g$.
Tactics are specified using the following notation:
\begin{center}
\begin{tabular}{c} \\
$goal$ \\ \hline \hline
$goal_1\ \ \ goal_2 \ \ \ \cdots\ \ \ goal_n$ \\
\end{tabular}
\end{center}
\noindent For example, a tactic called {\small\verb%CONJ_TAC%} is described by
\begin{center}
\begin{tabular}{c} \\
$ t_1${\small\verb% /\ %}$t_2$ \\ \hline \hline
$t_1\ \ \ \ \ \ \ t_2$ \\
\end{tabular}
\end{center}
\noindent Thus {\small\verb%CONJ_TAC%} reduces a goal of the form
{\small\verb%(%}$\Gamma${\small\verb%,"%}$t_1${\small\verb%/\%}$t_2${\small\verb%")%}
to subgoals
{\small\verb%(%}$\Gamma${\small\verb%,"%}$t_1${\small\verb%")%} and {\small\verb%(%}$\Gamma${\small\verb%,"%}$t_2${\small\verb%")%}.
The fact that the assumptions of the top-level goal
are propagated unchanged to the two subgoals is indicated by the absence
of assumptions in the notation.
Another example is {\small\verb%INDUCT_TAC%}, the tactic for doing mathematical induction
on the natural numbers:
\begin{center}
\begin{tabular}{c} \\
{\small\verb%!%}$n${\small\verb%.%}$t[n]$ \\ \hline \hline
$t[${\small\verb%0%}$]$ {\small\verb% %} $\{t[n]\}\ t[${\small\verb%SUC %}$n]$
\end{tabular}
\end{center}
{\small\verb%INDUCT_TAC%} reduces a goal
{\small\verb%(%}$\Gamma${\small\verb%,"!%}$n${\small\verb%.%}$t[n]${\small\verb%")%} to a basis subgoal
{\small\verb%(%}$\Gamma${\small\verb%,"%}$t[${\small\verb%0%}$]${\small\verb%")%}
and an induction step subgoal
{\small\verb%(%}$\Gamma\cup\{${\small\verb%"%}$t[n]${\small\verb%"%}$\}${\small\verb%,"%}$t[${\small\verb%SUC %}$n]${\small\verb%")%}.
The extra induction assumption {\small\verb%"%}$t[n]${\small\verb%"%}
is indicated in the tactic notation with set brackets.
\begin{session}\begin{verbatim}
#INDUCT_TAC([], "!m n. m+n = n+m");;
([([], "!n. 0 + n = n + 0");
(["!n. m + n = n + m"], "!n. (SUC m) + n = n + (SUC m)")],
-)
: subgoals
\end{verbatim}\end{session}
\noindent The first subgoal is the basis case and the second subgoal is
the step case.
Tactics generally fail (in the \ML\ sense) if they are applied to
inappropriate
goals. For example, {\small\verb%CONJ_TAC%} will fail if it is applied to a goal whose
conclusion is not a conjunction. Some tactics never fail, for example
{\small\verb%ALL_TAC%}
\begin{center}
\begin{tabular}{c} \\
$t$ \\ \hline \hline
$t$
\end{tabular}
\end{center}
\noindent is the `identity tactic'; it reduces a goal
{\small\verb%(%}$\Gamma${\small\verb%,%}$t${\small\verb%)%}
to the single
subgoal {\small\verb%(%}$\Gamma${\small\verb%,%}$t${\small\verb%)%}---\ie\
it has no effect. {\small\verb%ALL_TAC%} is useful for writing
complex tactics using tacticals (\eg\ see the definition of
{\small\verb%REPEAT%} in Section~\ref{tacticals}).
\section{Using tactics to prove theorems}
\label{using-tactics}
Suppose goal $g$ is to be solved. If $g$
is simple it might be possible
to immediately think up a tactic, $T$
say, which reduces it to the empty list of
subgoals. If this is the case then executing:
$\ ${\small\verb% let %}$gl${\small\verb%,%}$p${\small\verb% = %}$T\ g$
\noindent will bind $p$ to a function which when applied to the empty list
of theorems yields a theorem $th$ achieving $g$.
(The declaration above
will also bind $gl$ to the empty list of goals.) Thus a theorem achieving
$g$ can be computed by executing:
$\ ${\small\verb% let %}$th${\small\verb% = %}$p${\small\verb%[]%}
\noindent This will be illustrated using \ml{REWRITE\_TAC} which takes a list
of equations (empty in the example that follows) and tries to prove a goal
by rewriting with these equations together with
\ml{basic\_rewrites}:
\begin{session}\begin{verbatim}
#let goal2 = ([], "T /\ x ==> x \/ (y /\ F)");;
goal2 = ([], "T /\ x ==> x \/ y /\ F") : (* list # term)
#REWRITE_TAC [] goal2;;
([], -) : subgoals
#snd it [];;
|- T /\ x ==> x \/ y /\ F
\end{verbatim}\end{session}
\noindent Proved theorems are usually stored in the current theory
so that
they can be used in subsequent sessions.
The built-in function
\ml{prove\_thm} of
\ML\ type {\small\verb%(string # term # tactic) -> thm%} facilitates the use
of tactics:
{\small\verb%prove_thm(`foo`,%}$t${\small\verb%,%}$T${\small\verb%)%} proves
the goal {\small\verb%([],%}$t${\small\verb%)%} (\ie\ the goal with no
assumptions and conclusion $t$) using tactic $T$ and saves the resulting
theorem with name {\small\verb%foo%} on the current theory.
If the theorem is not to be saved, the function \ml{prove} of type
{\small\verb%(term # tactic) -> thm%} can be used. Evaluating
{\small\verb%prove(%}$t${\small\verb%,%}$T${\small\verb%)%} proves the goal
{\small\verb%([],%}$t${\small\verb%)%} using $T$ and returns the result without
saving it. In both cases the evaluation fails if $T$ does not solve the
goal {\small\verb%([],%}$t${\small\verb%)%}.
When conducting a proof that involves many subgoals and tactics, it is necessary
to keep track of all the justification functions
and compose them in the correct order. While
this is feasible even in large proofs, it is tedious. \HOL\ provides a package
for building and traversing the tree of subgoals, stacking the justification functions and
applying them properly; this package was originally implemented for \LCF\ by
Larry Paulson.
The subgoal package implements a simple framework for interactive proof. A proof
tree is created and traversed top-down. The current goal can be expanded
into subgoals using a tactic; the subgoals are pushed onto a goal
stack and the justification function onto a proof stack.
Subgoals can be considered in any order. If the tactic solves a
subgoal (\ie\ returns an empty subgoal list), then the package proceeds to the
next subgoal in the tree.
The function \ml{set\_goal} of type \ml{goal -> void}
initializes the subgoal package with a new goal. Usually
top-level goals have no assumptions; the function \ml{g} is useful
in this case and is defined by:
\begin{hol}\begin{verbatim}
let g t = set_goal([],t)
\end{verbatim}\end{hol}
To illustrate the subgoal package the trivial theorem
$\vdash \uquant{m}m+0=m$ will be proved from the definition of addition:
\begin{session}\begin{verbatim}
#ADD;;
Definition ADD autoloaded from theory `arithmetic`.
ADD = |- (!n. 0 + n = n) /\ (!m n. (SUC m) + n = SUC(m + n))
|- (!n. 0 + n = n) /\ (!m n. (SUC m) + n = SUC(m + n))
\end{verbatim}\end{session}
\noindent Notice that \ml{ADD} specifies
$0+m=m$ but not $m+0=m$. Of course, $\uquant{m\ n}m+n = n+m$ is true, but the first step of the proof is to show
$\uquant{m}m+0=m$ from the definition of addition.
\setcounter{sessioncount}{1}
\begin{session}\begin{verbatim}
#g "!m. m+0=m";;
"!m. m + 0 = m"
() : void
\end{verbatim}\end{session}
\noindent This sets up the goal. Next the goal is split into a basis and step case
with \ml{INDUCT\_TAC}. To do this the function \ml{e} (or, equivalently,
\ml{expand}) is used. This applies a tactic to the top goal on the stack, then
pushes the resulting subgoals onto the goal stack, then prints the resulting
subgoals. If there are no subgoals, the justification function is applied to the
theorems solving the subgoals that have been proved and the resulting theorems are
printed.
\begin{session}\begin{verbatim}
#e INDUCT_TAC;;
OK..
2 subgoals
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
"0 + 0 = 0"
\end{verbatim}\end{session}
\noindent The top of the goal stack is printed last. The basis case
is an instance of the definition of addition, so is solved by rewriting with
\ml{ADD}.
\begin{session}\begin{verbatim}
#e(REWRITE_TAC[ADD]);;
OK..
goal proved
|- 0 + 0 = 0
Previous subproof:
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
\end{verbatim}\end{session}
\noindent The basis is solved and the goal
stack popped so that its top is now the step case, namely showing
that {\small\verb%(SUC m) + 0 = SUC m%} under the assumption
{\small\verb%m + 0 = m%}. This goal can be solved by rewriting first
with the definition of addition:
\begin{session}\begin{verbatim}
#e(REWRITE_TAC[ADD]);;
OK..
"SUC(m + 0) = SUC m"
[ "m + 0 = m" ]
\end{verbatim}\end{session}
\noindent and then with the assumption \ml{m+0=m}. The tactic
\ml{ASM\_REWRITE\_TAC} is used to rewrite with the assumptions of a goal. It is
just like \ml{REWRITE\_TAC} except that it adds the assumptions to the list of
equations used for rewriting. For the example here no equations besides the
assumptions are needed, so \ml{ASM\_REWRITE\_TAC} is given the empty list of
equations.
\begin{session}\begin{verbatim}
#e(ASM_REWRITE_TAC[]);;
OK..
goal proved
. |- SUC(m + 0) = SUC m
. |- (SUC m) + 0 = SUC m
|- !m. m + 0 = m
Previous subproof:
goal proved
\end{verbatim}\end{session}
\noindent The top goal is solved, hence the preceding goal (the step case)
is solved too, and since the basis is already solved, the main goal is solved.
The theorem achieving the goal can be extracted from the subgoal package with
\ml{top\_thm}:
\begin{session}\begin{verbatim}
#top_thm();;
|- !m. m + 0 = m
\end{verbatim}\end{session}
The proof just done can be `optimized'. For example, instead
of first rewriting with \ml{ADD} (box 4) and then with the assumptions
(box 5), a single rewriting with \ml{ADD} and the assumptions would suffice.
To illustrate, the last two steps of the proof will be `undone' using the function
\ml{backup} which restores the previous state of the goal and theorem stacks.
\begin{session}\begin{verbatim}
#backup();;
"SUC(m + 0) = SUC m"
[ "m + 0 = m" ]
() : void
#backup();;
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
\end{verbatim}\end{session}
\noindent The proof can now be completed in one step instead of two:
\begin{session}\begin{verbatim}
#e(ASM_REWRITE_TAC[ADD]);;
OK..
goal proved
. |- (SUC m) + 0 = SUC m
|- !m. m + 0 = m
Previous subproof:
goal proved
\end{verbatim}\end{session}
The order in which goals are attacked can be adjusted using \ml{rotate\ }$n$
which rotates the goal stack by $n$. For example:
\begin{session}\begin{verbatim}
#backup();backup();;
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
2 subgoals
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
"0 + 0 = 0"
() : void
#rotate 1;;
2 subgoals
"0 + 0 = 0"
"(SUC m) + 0 = SUC m"
[ "m + 0 = m" ]
\end{verbatim}\end{session}
\noindent The top goal is now the step case not the basis case, so expanding
with a tactic will apply the tactic to the step case.
\begin{session}\begin{verbatim}
e(ASM_REWRITE_TAC[ADD]);;
OK..
goal proved
. |- (SUC m) + 0 = SUC m
Previous subproof:
"0 + 0 = 0"
\end{verbatim}\end{session}
It is possible to do the whole proof in one step, but this requires a compound
tactic built using the {\it tactical\/}\footnote{This word was invented by Robin
Milner: `tactical' is to `tactic` as `functional' is to `function'.} \ml{THENL}.
Tacticals are higher order operations for combining tactics.
\section{Tacticals}
\label{tacticals}
A {\it tactical\/}
is an \ML\ function that returns a tactic (or tactics) as result.
Tacticals may take various parameters; this is reflected in the various
\ML\ types that the built-in tacticals have. Some important tacticals in
the \HOL\ system
are listed below.
\subsection{\tt THENL : tactic -> tactic list -> tactic}
If tactic $T$ produces $n$ subgoals and $T_1$, $\ldots$ ,
$T_n$ are tactics
then $T${\small\verb% THENL%} {\small\verb%[%}$T_1${\small\verb%;%}$\ldots${\small\verb%;%}$T_n${\small\verb%]%}
is a tactic which first applies $T$ and then
applies $T_i$ to the $i$th subgoal produced by $T$.
The tactical {\small\verb%THENL%} is useful if one wants to do different
things to different subgoals.
\ml{THENL} can be illustrated by doing the proof of $\vdash \uquant{m}m+0=m$ in
one step.
\setcounter{sessioncount}{1}
\begin{session}\begin{verbatim}
#g "!m. m + 0 = m";;
"!m. m + 0 = m"
() : void
#e(INDUCT_TAC THENL [REWRITE_TAC[ADD];ASM_REWRITE_TAC[ADD]]);;
OK..
goal proved
|- !m. m + 0 = m
Previous subproof:
goal proved
() : void
\end{verbatim}\end{session}
\noindent The compound tactic
{\small\verb%INDUCT_TAC THENL [REWRITE_TAC[ADD];ASM_REWRITE_TAC[ADD]]%}
first applies \ml{INDUCT\_TAC} and then applies
\ml{REWRITE\_TAC[ADD]} to the first subgoal (the basis) and
\ml{ASM\_REWRITE\_TAC[ADD]} to the second subgoal (the step).
The tactical {\small\verb%THENL%} is useful for doing different things to different
subgoals. The tactical \ml{THEN} can be used to apply the same tactic to all
subgoals.
\subsection{\tt THEN : tactic -> tactic -> tactic}\label{THEN}
The tactical {\small\verb%THEN%} is an \ML\ infix. If $T_1$ and $T_2$ are tactics,
then the \ML\ expression $T_1${\small\verb% THEN %}$T_2$ evaluates to a tactic
which first applies $T_1$ and then applies $T_2$ to all the subgoals produced
by $T_1$.
In fact,
\ml{ASM\_REWRITE\_TAC[ADD]} will solve the basis as well as the step
case of the induction for $\uquant{m}m+0=m$, so there is an even
simpler one-step proof than the one above:
\setcounter{sessioncount}{1}
\begin{session}\begin{verbatim}
#g "!m. m+0 = m";;
"!m. m + 0 = m"
() : void
#e(INDUCT_TAC THEN ASM_REWRITE_TAC[ADD]);;
OK..
goal proved
|- !m. m + 0 = m
Previous subproof:
goal proved
\end{verbatim}\end{session}
\noindent This is typical: it is common to use a single tactic for several
goals. Here, for example, are the first four consequences of the definition
\ml{ADD} of addition that are pre-proved when the built-in theory
\ml{arithmetic} \HOL\ is made.
\begin{hol}\begin{verbatim}
let ADD_0 =
prove
("!m. m + 0 = m",
INDUCT_TAC
THEN ASM_REWRITE_TAC[ADD]);;
\end{verbatim}\end{hol}
\begin{hol}\begin{verbatim}
let ADD_SUC =
prove
("!m n. SUC(m + n) = m + SUC n",
INDUCT_TAC
THEN ASM_REWRITE_TAC[ADD]);;
\end{verbatim}\end{hol}
\begin{hol}\begin{verbatim}
let ADD_CLAUSES =
prove
("(0 + m = m) /\
(m + 0 = m) /\
(SUC m + n = SUC(m + n)) /\
(m + SUC n = SUC(m + n))",
REWRITE_TAC[ADD;ADD_0;ADD_SUC]);;
\end{verbatim}\end{hol}
\begin{hol}\begin{verbatim}
let ADD_SYM =
prove
("!m n. m + n = n + m",
INDUCT_TAC
THEN ASM_REWRITE_TAC[ADD_0;ADD;ADD_SUC]);;
\end{verbatim}\end{hol}
\noindent These proofs are performed when the \HOL\ system is made and the
theorems are saved in the theory \ml{arithmetic}. The complete list of
proofs for this built-in theory can be found in the file
\ml{theories/mk\_arith\_thms.ml}.
\subsection{\tt ORELSE : tactic -> tactic -> tactic}\label{ORELSE}
The tactical {\small\verb%ORELSE%}
is an \ML\ infix. If $T_1$ and $T_2$ are tactics,
\index{tacticals!for alternation}
then $T_1${\small\verb% ORELSE %}$T_2$
evaluates to a tactic which applies $T_1$ unless that fails;
if it fails,
it applies $T_2$. \ml{ORELSE} is defined in \ML\
as a curried infix by
\begin{hol}
{\small\verb%(%}$T_1${\small\verb% ORELSE %}$T_2${\small\verb%)%} $g$
{\small\verb%=%} $T_1 g$ {\small\verb%?%} $T_2 g$
\end{hol}\index{alternation!of tactics|)}
\subsection{\tt REPEAT : tactic -> tactic}
If $T$ is a
tactic then {\small\verb%REPEAT %}$T$ is a tactic which repeatedly applies
$T$ until it fails. This can be illustrated in conjunction with
\ml{GEN\_TAC}, which is specified by:
\begin{center}
\begin{tabular}{c} \\
{\small\verb%!%}$x${\small\verb%.%}$t[x]$
\\ \hline \hline
$t[x']$
\\
\end{tabular}
\end{center}
\begin{itemize}
\item Where $x'$ is a variant of $x$
not free in the goal or the assumptions.
\end{itemize}
\noindent \ml{GEN\_TAC} strips off one quantifier;
\ml{REPEAT\ GEN\_TAC} strips off all quantifiers:
\begin{session}\begin{verbatim}
#g "!x y z. x+(y+z) = (x+y)+z";;
"!x y z. x + (y + z) = (x + y) + z"
() : void
#e GEN_TAC;;
OK..
"!y z. x + (y + z) = (x + y) + z"
() : void
#e(REPEAT GEN_TAC);;
OK..
"x + (y + z) = (x + y) + z"
\end{verbatim}\end{session}
\section{Some tactics built into HOL}
This section contains a summary of some of the tactics built into the \HOL\ system
(including those already discussed).
The tactics given here are those that are used in the parity checking case
study.
Recall that the \ML\ type {\small\verb%thm_tactic%} abbreviates {\small\verb%theorem->tactic%},
and the type {\small\verb%conv%}\footnote{The type
{\small{\tt conv}} comes from Larry Paulson's theory of conversions
\cite{lcp_rewrite}.} abbreviates {\small\verb%term->thm%}.
\subsection{\tt REWRITE\_TAC : thm list -> tactic}
\label{rewrite}
\begin{itemize}
\item{\bf Summary:} {\small\verb%REWRITE_TAC[%}$th_1${\small\verb%;%}$\ldots${\small\verb%;%}$th_n${\small\verb%]%}
simplifies the goal by rewriting
it with the explicitly given theorems $th_1$, $\ldots$ , $th_n$,
and various built-in rewriting rules.
\begin{center}
\begin{tabular}{c} \\
$\{t_1, \ldots , t_m\}t$
\\ \hline \hline
$\{t_1, \ldots , t_m\}t'$
\\
\end{tabular}
\end{center}
\noindent where $t'$ is obtained from $t$ by rewriting with
\begin{enumerate}
\item $th_1$, $\ldots$ , $th_n$ and
\item the standard rewrites held in the \ML\ variable {\small\verb%basic_rewrites%}.
\end{enumerate}
\item{\bf Uses:} Simplifying goals using previously proved theorems.
\item{\bf Other rewriting tactics} (based on {\small\verb%REWRITE_TAC%}):
\begin{enumerate}
\item {\small\verb%ASM_REWRITE_TAC%} adds the assumptions of the goal to the list of
theorems used for rewriting.
\item {\small\verb%FILTER_ASM_REWRITE_TAC %}$p${\small\verb% [%}$th_1${\small\verb%;%}$\ldots${\small\verb%;%}$th_n${\small\verb%]%}
simplifies the goal by rewriting
it with the explicitly given theorems $th_1$ , $\ldots$ , $th_n$ ,
together with those
assumptions of the goal which satisfy the predicate $p$ and also
the built-in rewrites in the \ML\ variable {\small\verb%basic_rewrites%}.
\item {\small\verb%PURE_ASM_REWRITE_TAC%} is like {\small\verb%ASM_REWRITE_TAC%}, but it
doesn't use any built-in rewrites.
\item {\small\verb%PURE_REWRITE_TAC%} uses neither the assumptions nor the built-in
rewrites.
\end{enumerate}
\end{itemize}
\subsection{\tt CONJ\_TAC : tactic}\label{CONJTAC}
\begin{itemize}
\item{\bf Summary:} Splits a
goal {\small\verb%"%}$t_1${\small\verb%/\%}$t_2${\small\verb%"%} into two subgoals {\small\verb%"%}$t_1${\small\verb%"%}
and {\small\verb%"%}$t_2${\small\verb%"%}.
\begin{center}
\begin{tabular}{c} \\
$t_1${\small\verb% /\ %}$t_2$
\\ \hline \hline
$t_1\ \ \ \ \ \ t_2$
\\
\end{tabular}
\end{center}
\item{\bf Uses:} Solving conjunctive goals.
{\small\verb%CONJ_TAC%} is invoked by {\small\verb%STRIP_TAC%} (see below).
\end{itemize}
\subsection{\tt EQ\_TAC : tactic}\label{EQTAC}
\begin{itemize}
\item{\bf Summary:}
{\small\verb%EQ_TAC%}
splits an equational goal into two implications (the `if-case' and
the `only-if' case):
\begin{center}
\begin{tabular}{c} \\
$u\ \ml{=}\ v$
\\ \hline \hline
$u\ \ml{==>}\ v\ \ \ \ \ v\ \ml{==>}\ u$
\\
\end{tabular}
\end{center}
\item{\bf Use:} Proving logical equivalences, \ie\ goals of the form
``$u$\ml{=}$v$'' where $u$ and $v$ are boolean terms.
\end{itemize}
\subsection{\tt DISCH\_TAC : tactic}\label{DISCHTAC}
\begin{itemize}
\item{\bf Summary:} Moves the antecedent
of an implicative goal into the assumptions.
\begin{center}
\begin{tabular}{c} \\
$u${\small\verb% ==> %}$v$
\\ \hline \hline
$\{u\}v$
\\
\end{tabular}
\end{center}
\item{\bf Uses:} Solving goals of the form
{\small\verb%"%}$u${\small\verb% ==> %}$v${\small\verb%"%} by assuming {\small\verb%"%}$u${\small\verb%"%} and then solving
{\small\verb%"%}$v${\small\verb%"%}.
{\small\verb%STRIP_TAC%} (see below) will invoke {\small\verb%DISCH_TAC%} on implicative goals.
\end{itemize}
\subsection{\tt GEN\_TAC : tactic}
\begin{itemize}
\item{\bf Summary:} Strips off one universal quantifier.
\begin{center}
\begin{tabular}{c} \\
{\small\verb%!%}$x${\small\verb%.%}$t[x]$
\\ \hline \hline
$t[x']$
\\
\end{tabular}
\end{center}
\noindent Where $x'$ is a variant of $x$
not free in the goal or the assumptions.
\item{\bf Uses:} Solving universally quantified goals.
{\small\verb%REPEAT GEN_TAC%} strips off all
universal quantifiers and is often the first thing one does in a proof.
{\small\verb%STRIP_TAC%} (see below) applies {\small\verb%GEN_TAC%} to universally quantified goals.
\end{itemize}
\subsection{\tt IMP\_RES\_TAC : tactic}
\begin{itemize}
\item{\bf Summary:} {\small\verb%IMP_RES_TAC %}$th$ does a limited amount of
automated theorem proving in the form of forward inference; it
`resolves' the theorem $th$ with the
assumptions of the goal
and adds any new results to the assumptions. The specification for
\ml{IMP\_RES\_TAC} is:
\begin{center}
\begin{tabular}{c} \\
$\{t_1,\ldots,t_m\}t$
\\ \hline \hline
$\{t_1,\ldots,t_m,u_1,\ldots,u_n\}t$
\\
\end{tabular}
\end{center}
\noindent where $u_1$, $\dots$, $u_n$
are derived by `resolving' the theorem $th$ with the existing assumptions
$t_1$, $\dots$, $t_m$.
Resolution in \HOL\ is not classical resolution, but just Modus Ponens with
one-way pattern matching (not unification) and term and type instantiation. The
general case is where $th$ is of the canonical form
$\ \ \ ${\small\verb%|- !%}$x_1$$\ldots x_p${\small\verb%.%}$v_1$ {\small\verb%==>%} $v_2$ {\small\verb%==>%} $\ldots$ {\small\verb%==>%} $v_q$ {\small\verb%==>%} $v$
\noindent {\small\verb%IMP_RES_TAC %}$th$ then tries to specialize $x_1$,
$\dots$, $x_p$ in succession so that $v_1$, $\dots$, $v_q$ match members of
$\{t_1,\ldots ,t_m\}$. Each time a match is found for some antecedent $v_i$,
for $i$ successively equal to $1$, $2$, \dots, $q$, a term and type
instantiation is made and the rule of Modus Ponens is applied. If all the
antecedents $v_i$ (for $1 \leq i \leq q$) can be dismissed in this way, then
the appropriate instance of $v$ is added to the assumptions. Otherwise, if only
some initial sequence $v_1$, \dots, $v_k$ (for some $k$ where $1 < k < q$) of
the assumptions can be dismissed, then the remaining implication:
$\ \ \ ${\small\verb%|- %} $v_{k+1}$ {\small\verb%==>%} $\ldots$ {\small\verb%==>%} $v_q$ {\small\verb%==>%} $v$
\noindent is added to the assumptions.
For a more detailed description of resolution and \ml{IMP\_RES\_TAC},
see \DESCRIPTION\ and \REFERENCE.
\item{\bf Uses:} Deriving new results from a previously proved implicative
theorem, in combination with the current assumptions, so that
subsequent tactics can use these new results.
\end{itemize}
\subsection{\tt STRIP\_TAC : tactic}
\begin{itemize}
\item{\bf Summary:} Breaks a goal apart.
{\small\verb%STRIP_TAC%} removes one outer connective from the goal, using
{\small\verb%CONJ_TAC%}, {\small\verb%DISCH_TAC%}, {\small\verb%GEN_TAC%}, \etc\
If the goal is
$t_1${\small\verb%/\%}$\cdots${\small\verb%/\%}$t_n${\small\verb% ==> %}$t$
then {\small\verb%DISCH_TAC%} makes each $t_i$ into a separate assumption.
\item{\bf Uses:} Useful for splitting a goal up into manageable pieces.
Often the best thing to do first is {\small\verb%REPEAT STRIP_TAC%}.
\end{itemize}
\subsection{\tt SUBST\_TAC : thm list -> thm}
\begin{itemize}
\item{\bf Summary:}
{\small\verb%SUBST_TAC[|-%}$u_1${\small\verb%=%}$v_1${\small\verb%;%}$\ldots${\small\verb%;|-%}$u_n${\small\verb%=%}$v_n${\small\verb%]%}
converts a goal $t[u_1,\ldots ,u_n]$
to the subgoal form $t[v_1,\ldots ,v_n]$.
\item{\bf Uses:}
To make replacements for terms in
situations in which {\small\verb%REWRITE_TAC%} is too
general or would loop.
\end{itemize}
\subsection{\tt ACCEPT\_TAC : thm -> tactic}\label{ACCEPTTAC}
\begin{itemize}
\item{\bf Summary:} {\small\verb%ACCEPT_TAC %}$th$
is a tactic that solves any goal that is
achieved by $th$.
\item{\bf Use:} Incorporating forward proofs, or theorems already
proved, into goal directed proofs.
For example, one might reduce a goal $g$ to
subgoals $g_1$, $\dots$, $g_n$
using a tactic $T$ and then prove theorems $th_1$ , $\dots$, $th_n$
respectively achieving
these goals by forward proof. The tactic
\[\ml{ T THENL[ACCEPT\_TAC }th_1\ml{;}\ldots\ml{;ACCEPT\_TAC }th_n\ml{]}
\]
would then solve $g$, where \ml{THENL}
\index{THENL@\ml{THENL}} is the tactical that applies
the respective elements of the tactic list to the subgoals produced
by \ml{T}.
\end{itemize}
\subsection{\tt ALL\_TAC : tactic}
\begin{itemize}
\item{\bf Summary:} Identity tactic for the tactical {\small\verb%THEN%}
(see \DESCRIPTION).
\item{\bf Uses:}
\begin{enumerate}
\item Writing tacticals (see description of {\small\verb%REPEAT%}
in \DESCRIPTION).
\item With {\small\verb%THENL%}; for example, if tactic $T$ produces two subgoals
and we want to apply $T_1$
to the first one but to do nothing to the second, then
the tactic to use is $T${\small\verb% THENL[%}$T_1${\small\verb%;ALL_TAC]%}.
\end{enumerate}
\end{itemize}
\subsection{\tt NO\_TAC : tactic}
\begin{itemize}
\item{\bf Summary:} Tactic that always fails.
\item{\bf Uses:} Writing tacticals.
\end{itemize}
|