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
|
(* ========================================================================= *)
(* Inductive (or free recursive) types. *)
(* *)
(* John Harrison, University of Cambridge Computer Laboratory *)
(* *)
(* (c) Copyright, University of Cambridge 1998 *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* ========================================================================= *)
needs "grobner.ml";;
(* ------------------------------------------------------------------------- *)
(* Abstract left inverses for binary injections (we could construct them...) *)
(* ------------------------------------------------------------------------- *)
let INJ_INVERSE2 = prove
(`!P:A->B->C.
(!x1 y1 x2 y2. (P x1 y1 = P x2 y2) <=> (x1 = x2) /\ (y1 = y2))
==> ?X Y. !x y. (X(P x y) = x) /\ (Y(P x y) = y)`,
GEN_TAC THEN DISCH_TAC THEN
EXISTS_TAC `\z:C. @x:A. ?y:B. P x y = z` THEN
EXISTS_TAC `\z:C. @y:B. ?x:A. P x y = z` THEN
REPEAT GEN_TAC THEN ASM_REWRITE_TAC[BETA_THM] THEN
CONJ_TAC THEN MATCH_MP_TAC SELECT_UNIQUE THEN GEN_TAC THEN BETA_TAC THEN
EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
W(EXISTS_TAC o rand o snd o dest_exists o snd) THEN REFL_TAC);;
(* ------------------------------------------------------------------------- *)
(* Define an injective pairing function on ":num". *)
(* ------------------------------------------------------------------------- *)
let NUMPAIR = new_definition
`NUMPAIR x y = (2 EXP x) * (2 * y + 1)`;;
let NUMPAIR_INJ_LEMMA = prove
(`!x1 y1 x2 y2. (NUMPAIR x1 y1 = NUMPAIR x2 y2) ==> (x1 = x2)`,
REWRITE_TAC[NUMPAIR] THEN REPEAT(INDUCT_TAC THEN GEN_TAC) THEN
ASM_REWRITE_TAC[EXP; GSYM MULT_ASSOC; ARITH; EQ_MULT_LCANCEL;
NOT_SUC; GSYM NOT_SUC; SUC_INJ] THEN
DISCH_THEN(MP_TAC o AP_TERM `EVEN`) THEN
REWRITE_TAC[EVEN_MULT; EVEN_ADD; ARITH]);;
let NUMPAIR_INJ = prove
(`!x1 y1 x2 y2. (NUMPAIR x1 y1 = NUMPAIR x2 y2) <=> (x1 = x2) /\ (y1 = y2)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
FIRST_ASSUM(SUBST_ALL_TAC o MATCH_MP NUMPAIR_INJ_LEMMA) THEN
POP_ASSUM MP_TAC THEN REWRITE_TAC[NUMPAIR] THEN
REWRITE_TAC[EQ_MULT_LCANCEL; EQ_ADD_RCANCEL; EXP_EQ_0; ARITH]);;
let NUMPAIR_DEST = new_specification
["NUMFST"; "NUMSND"]
(MATCH_MP INJ_INVERSE2 NUMPAIR_INJ);;
(* ------------------------------------------------------------------------- *)
(* Also, an injective map bool->num->num (even easier!) *)
(* ------------------------------------------------------------------------- *)
let NUMSUM = new_definition
`NUMSUM b x = if b then SUC(2 * x) else 2 * x`;;
let NUMSUM_INJ = prove
(`!b1 x1 b2 x2. (NUMSUM b1 x1 = NUMSUM b2 x2) <=> (b1 = b2) /\ (x1 = x2)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
POP_ASSUM(MP_TAC o REWRITE_RULE[NUMSUM]) THEN
DISCH_THEN(fun th -> MP_TAC th THEN MP_TAC(AP_TERM `EVEN` th)) THEN
REPEAT COND_CASES_TAC THEN REWRITE_TAC[EVEN; EVEN_DOUBLE] THEN
REWRITE_TAC[SUC_INJ; EQ_MULT_LCANCEL; ARITH]);;
let NUMSUM_DEST = new_specification
["NUMLEFT"; "NUMRIGHT"]
(MATCH_MP INJ_INVERSE2 NUMSUM_INJ);;
(* ------------------------------------------------------------------------- *)
(* Injection num->Z, where Z == num->A->bool. *)
(* ------------------------------------------------------------------------- *)
let INJN = new_definition
`INJN (m:num) = \(n:num) (a:A). n = m`;;
let INJN_INJ = prove
(`!n1 n2. (INJN n1 :num->A->bool = INJN n2) <=> (n1 = n2)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
POP_ASSUM(MP_TAC o C AP_THM `n1:num` o REWRITE_RULE[INJN]) THEN
DISCH_THEN(MP_TAC o C AP_THM `a:A`) THEN REWRITE_TAC[BETA_THM]);;
(* ------------------------------------------------------------------------- *)
(* Injection A->Z, where Z == num->A->bool. *)
(* ------------------------------------------------------------------------- *)
let INJA = new_definition
`INJA (a:A) = \(n:num) b. b = a`;;
let INJA_INJ = prove
(`!a1 a2. (INJA a1 = INJA a2) <=> (a1:A = a2)`,
REPEAT GEN_TAC THEN REWRITE_TAC[INJA; FUN_EQ_THM] THEN EQ_TAC THENL
[DISCH_THEN(MP_TAC o SPEC `a1:A`) THEN REWRITE_TAC[];
DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[]]);;
(* ------------------------------------------------------------------------- *)
(* Injection (num->Z)->Z, where Z == num->A->bool. *)
(* ------------------------------------------------------------------------- *)
let INJF = new_definition
`INJF (f:num->(num->A->bool)) = \n. f (NUMFST n) (NUMSND n)`;;
let INJF_INJ = prove
(`!f1 f2. (INJF f1 :num->A->bool = INJF f2) <=> (f1 = f2)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
REWRITE_TAC[FUN_EQ_THM] THEN
MAP_EVERY X_GEN_TAC [`n:num`; `m:num`; `a:A`] THEN
POP_ASSUM(MP_TAC o REWRITE_RULE[INJF]) THEN
DISCH_THEN(MP_TAC o C AP_THM `a:A` o C AP_THM `NUMPAIR n m`) THEN
REWRITE_TAC[NUMPAIR_DEST]);;
(* ------------------------------------------------------------------------- *)
(* Injection Z->Z->Z, where Z == num->A->bool. *)
(* ------------------------------------------------------------------------- *)
let INJP = new_definition
`INJP f1 f2:num->A->bool =
\n a. if NUMLEFT n then f1 (NUMRIGHT n) a else f2 (NUMRIGHT n) a`;;
let INJP_INJ = prove
(`!(f1:num->A->bool) f1' f2 f2'.
(INJP f1 f2 = INJP f1' f2') <=> (f1 = f1') /\ (f2 = f2')`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
ONCE_REWRITE_TAC[FUN_EQ_THM] THEN REWRITE_TAC[AND_FORALL_THM] THEN
X_GEN_TAC `n:num` THEN POP_ASSUM(MP_TAC o REWRITE_RULE[INJP]) THEN
DISCH_THEN(MP_TAC o GEN `b:bool` o C AP_THM `NUMSUM b n`) THEN
DISCH_THEN(fun th -> MP_TAC(SPEC `T` th) THEN MP_TAC(SPEC `F` th)) THEN
ASM_SIMP_TAC[NUMSUM_DEST; ETA_AX]);;
(* ------------------------------------------------------------------------- *)
(* Now, set up "constructor" and "bottom" element. *)
(* ------------------------------------------------------------------------- *)
let ZCONSTR = new_definition
`ZCONSTR c i r :num->A->bool
= INJP (INJN (SUC c)) (INJP (INJA i) (INJF r))`;;
let ZBOT = new_definition
`ZBOT = INJP (INJN 0) (@z:num->A->bool. T)`;;
let ZCONSTR_ZBOT = prove
(`!c i r. ~(ZCONSTR c i r :num->A->bool = ZBOT)`,
REWRITE_TAC[ZCONSTR; ZBOT; INJP_INJ; INJN_INJ; NOT_SUC]);;
(* ------------------------------------------------------------------------- *)
(* Carve out an inductively defined set. *)
(* ------------------------------------------------------------------------- *)
let ZRECSPACE_RULES,ZRECSPACE_INDUCT,ZRECSPACE_CASES =
new_inductive_definition
`ZRECSPACE (ZBOT:num->A->bool) /\
(!c i r. (!n. ZRECSPACE (r n)) ==> ZRECSPACE (ZCONSTR c i r))`;;
let recspace_tydef =
new_basic_type_definition "recspace" ("_mk_rec","_dest_rec")
(CONJUNCT1 ZRECSPACE_RULES);;
(* ------------------------------------------------------------------------- *)
(* Define lifted constructors. *)
(* ------------------------------------------------------------------------- *)
let BOTTOM = new_definition
`BOTTOM = _mk_rec (ZBOT:num->A->bool)`;;
let CONSTR = new_definition
`CONSTR c i r :(A)recspace
= _mk_rec (ZCONSTR c i (\n. _dest_rec(r n)))`;;
(* ------------------------------------------------------------------------- *)
(* Some lemmas. *)
(* ------------------------------------------------------------------------- *)
let MK_REC_INJ = prove
(`!x y. (_mk_rec x :(A)recspace = _mk_rec y)
==> (ZRECSPACE x /\ ZRECSPACE y ==> (x = y))`,
REPEAT GEN_TAC THEN DISCH_TAC THEN
REWRITE_TAC[snd recspace_tydef] THEN
DISCH_THEN(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
ASM_REWRITE_TAC[]);;
let DEST_REC_INJ = prove
(`!x y. (_dest_rec x = _dest_rec y) <=> (x:(A)recspace = y)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
POP_ASSUM(MP_TAC o AP_TERM
`_mk_rec:(num->A->bool)->(A)recspace`) THEN
REWRITE_TAC[fst recspace_tydef]);;
(* ------------------------------------------------------------------------- *)
(* Show that the set is freely inductively generated. *)
(* ------------------------------------------------------------------------- *)
let CONSTR_BOT = prove
(`!c i r. ~(CONSTR c i r :(A)recspace = BOTTOM)`,
REPEAT GEN_TAC THEN REWRITE_TAC[CONSTR; BOTTOM] THEN
DISCH_THEN(MP_TAC o MATCH_MP MK_REC_INJ) THEN
REWRITE_TAC[ZCONSTR_ZBOT; ZRECSPACE_RULES] THEN
MATCH_MP_TAC(CONJUNCT2 ZRECSPACE_RULES) THEN
REWRITE_TAC[fst recspace_tydef; snd recspace_tydef]);;
let CONSTR_INJ = prove
(`!c1 i1 r1 c2 i2 r2. (CONSTR c1 i1 r1 :(A)recspace = CONSTR c2 i2 r2) <=>
(c1 = c2) /\ (i1 = i2) /\ (r1 = r2)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
POP_ASSUM(MP_TAC o REWRITE_RULE[CONSTR]) THEN
DISCH_THEN(MP_TAC o MATCH_MP MK_REC_INJ) THEN
W(C SUBGOAL_THEN ASSUME_TAC o funpow 2 lhand o snd) THENL
[CONJ_TAC THEN MATCH_MP_TAC(CONJUNCT2 ZRECSPACE_RULES) THEN
REWRITE_TAC[fst recspace_tydef; snd recspace_tydef];
ASM_REWRITE_TAC[] THEN REWRITE_TAC[ZCONSTR] THEN
REWRITE_TAC[INJP_INJ; INJN_INJ; INJF_INJ; INJA_INJ] THEN
ONCE_REWRITE_TAC[FUN_EQ_THM] THEN BETA_TAC THEN
REWRITE_TAC[SUC_INJ; DEST_REC_INJ]]);;
let CONSTR_IND = prove
(`!P. P(BOTTOM) /\
(!c i r. (!n. P(r n)) ==> P(CONSTR c i r))
==> !x:(A)recspace. P(x)`,
REPEAT STRIP_TAC THEN
MP_TAC(SPEC `\z:num->A->bool. ZRECSPACE(z) /\ P(_mk_rec z)`
ZRECSPACE_INDUCT) THEN
BETA_TAC THEN ASM_REWRITE_TAC[ZRECSPACE_RULES; GSYM BOTTOM] THEN
W(C SUBGOAL_THEN ASSUME_TAC o funpow 2 lhand o snd) THENL
[REPEAT GEN_TAC THEN REWRITE_TAC[FORALL_AND_THM] THEN
REPEAT STRIP_TAC THENL
[MATCH_MP_TAC(CONJUNCT2 ZRECSPACE_RULES) THEN ASM_REWRITE_TAC[];
FIRST_ASSUM(ANTE_RES_THEN MP_TAC) THEN
REWRITE_TAC[CONSTR] THEN
RULE_ASSUM_TAC(REWRITE_RULE[snd recspace_tydef]) THEN
ASM_SIMP_TAC[ETA_AX]];
ASM_REWRITE_TAC[] THEN
DISCH_THEN(MP_TAC o SPEC `_dest_rec (x:(A)recspace)`) THEN
REWRITE_TAC[fst recspace_tydef] THEN
REWRITE_TAC[ITAUT `(a ==> a /\ b) <=> (a ==> b)`] THEN
DISCH_THEN MATCH_MP_TAC THEN
REWRITE_TAC[fst recspace_tydef; snd recspace_tydef]]);;
(* ------------------------------------------------------------------------- *)
(* Now prove the recursion theorem (this subcase is all we need). *)
(* ------------------------------------------------------------------------- *)
let CONSTR_REC = prove
(`!Fn:num->A->(num->(A)recspace)->(num->B)->B.
?f. (!c i r. f (CONSTR c i r) = Fn c i r (\n. f (r n)))`,
REPEAT STRIP_TAC THEN (MP_TAC o prove_inductive_relations_exist)
`(Z:(A)recspace->B->bool) BOTTOM b /\
(!c i r y. (!n. Z (r n) (y n)) ==> Z (CONSTR c i r) (Fn c i r y))` THEN
DISCH_THEN(CHOOSE_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC)) THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (ASSUME_TAC o GSYM)) THEN
SUBGOAL_THEN `!x. ?!y. (Z:(A)recspace->B->bool) x y` MP_TAC THENL
[W(MP_TAC o PART_MATCH rand CONSTR_IND o snd) THEN
DISCH_THEN MATCH_MP_TAC THEN CONJ_TAC THEN REPEAT GEN_TAC THENL
[FIRST_ASSUM(fun t -> GEN_REWRITE_TAC BINDER_CONV [GSYM t]) THEN
REWRITE_TAC[GSYM CONSTR_BOT; EXISTS_UNIQUE_REFL];
DISCH_THEN(MP_TAC o REWRITE_RULE[EXISTS_UNIQUE_THM; FORALL_AND_THM]) THEN
DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
DISCH_THEN(MP_TAC o REWRITE_RULE[SKOLEM_THM]) THEN
DISCH_THEN(X_CHOOSE_THEN `y:num->B` ASSUME_TAC) THEN
REWRITE_TAC[EXISTS_UNIQUE_THM] THEN
FIRST_ASSUM(fun th -> CHANGED_TAC(ONCE_REWRITE_TAC[GSYM th])) THEN
CONJ_TAC THENL
[EXISTS_TAC `(Fn:num->A->(num->(A)recspace)->(num->B)->B) c i r y` THEN
REWRITE_TAC[CONSTR_BOT; CONSTR_INJ; GSYM CONJ_ASSOC] THEN
REWRITE_TAC[UNWIND_THM1; RIGHT_EXISTS_AND_THM] THEN
EXISTS_TAC `y:num->B` THEN ASM_REWRITE_TAC[];
REWRITE_TAC[CONSTR_BOT; CONSTR_INJ; GSYM CONJ_ASSOC] THEN
REWRITE_TAC[UNWIND_THM1; RIGHT_EXISTS_AND_THM] THEN
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
REPEAT AP_TERM_TAC THEN ONCE_REWRITE_TAC[FUN_EQ_THM] THEN
X_GEN_TAC `w:num` THEN FIRST_ASSUM MATCH_MP_TAC THEN
EXISTS_TAC `w:num` THEN ASM_REWRITE_TAC[]]];
REWRITE_TAC[UNIQUE_SKOLEM_ALT] THEN
DISCH_THEN(X_CHOOSE_THEN `fn:(A)recspace->B` (ASSUME_TAC o GSYM)) THEN
EXISTS_TAC `fn:(A)recspace->B` THEN ASM_REWRITE_TAC[] THEN
REPEAT GEN_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN GEN_TAC THEN
FIRST_ASSUM(fun th -> GEN_REWRITE_TAC I [GSYM th]) THEN
REWRITE_TAC[BETA_THM]]);;
(* ------------------------------------------------------------------------- *)
(* The following is useful for coding up functions casewise. *)
(* ------------------------------------------------------------------------- *)
let FCONS = new_recursive_definition num_RECURSION
`(!a f. FCONS (a:A) f 0 = a) /\
(!a f n. FCONS (a:A) f (SUC n) = f n)`;;
let FCONS_UNDO = prove
(`!f:num->A. f = FCONS (f 0) (f o SUC)`,
GEN_TAC THEN REWRITE_TAC[FUN_EQ_THM] THEN
INDUCT_TAC THEN REWRITE_TAC[FCONS; o_THM]);;
let FNIL = new_definition
`FNIL (n:num) = @x:A. T`;;
(* ------------------------------------------------------------------------- *)
(* The initial mutual type definition function, with a type-restricted *)
(* recursion theorem. *)
(* ------------------------------------------------------------------------- *)
let define_type_raw =
(* ----------------------------------------------------------------------- *)
(* Handy utility to produce "SUC o SUC o SUC ..." form of numeral. *)
(* ----------------------------------------------------------------------- *)
let sucivate =
let zero = `0` and suc = `SUC` in
fun n -> funpow n (curry mk_comb suc) zero in
(* ----------------------------------------------------------------------- *)
(* Eliminate local "definitions" in hyps. *)
(* ----------------------------------------------------------------------- *)
let SCRUB_EQUATION eq (th,insts) = (*HA*)
let eq' = itlist subst (map (fun t -> [t]) insts) eq in
let l,r = dest_eq eq' in
(MP (INST [r,l] (DISCH eq' th)) (REFL r),(r,l)::insts) in
(* ----------------------------------------------------------------------- *)
(* Proves existence of model (inductively); use pseudo-constructors. *)
(* *)
(* Returns suitable definitions of constructors in terms of CONSTR, and *)
(* the rule and induction theorems from the inductive relation package. *)
(* ----------------------------------------------------------------------- *)
let justify_inductive_type_model =
let t_tm = `T` and n_tm = `n:num` and beps_tm = `@x:bool. T` in
let rec munion s1 s2 =
if s1 = [] then s2 else
let h1 = hd s1
and s1' = tl s1 in
try let _,s2' = remove (fun h2 -> h2 = h1) s2 in h1::(munion s1' s2')
with Failure _ -> h1::(munion s1' s2) in
fun def ->
let newtys,rights = unzip def in
let tyargls = itlist ((@) o map snd) rights [] in
let alltys = itlist (munion o C subtract newtys) tyargls [] in
let epstms = map (fun ty -> mk_select(mk_var("v",ty),t_tm)) alltys in
let pty =
try end_itlist (fun ty1 ty2 -> mk_type("prod",[ty1;ty2])) alltys
with Failure _ -> bool_ty in
let recty = mk_type("recspace",[pty]) in
let constr = mk_const("CONSTR",[pty,aty]) in
let fcons = mk_const("FCONS",[recty,aty]) in
let bot = mk_const("BOTTOM",[pty,aty]) in
let bottail = mk_abs(n_tm,bot) in
let mk_constructor n (cname,cargs) =
let ttys = map (fun ty -> if mem ty newtys then recty else ty) cargs in
let args = make_args "a" [] ttys in
let rargs,iargs = partition (fun t -> type_of t = recty) args in
let rec mk_injector epstms alltys iargs =
if alltys = [] then [] else
let ty = hd alltys in
try let a,iargs' = remove (fun t -> type_of t = ty) iargs in
a::(mk_injector (tl epstms) (tl alltys) iargs')
with Failure _ ->
(hd epstms)::(mk_injector (tl epstms) (tl alltys) iargs) in
let iarg =
try end_itlist (curry mk_pair) (mk_injector epstms alltys iargs)
with Failure _ -> beps_tm in
let rarg = itlist (mk_binop fcons) rargs bottail in
let conty = itlist mk_fun_ty (map type_of args) recty in
let condef = list_mk_comb(constr,[sucivate n; iarg; rarg]) in
mk_eq(mk_var(cname,conty),list_mk_abs(args,condef)) in
let rec mk_constructors n rights =
if rights = [] then [] else
(mk_constructor n (hd rights))::(mk_constructors (n + 1) (tl rights)) in
let condefs = mk_constructors 0 (itlist (@) rights []) in
let conths = map ASSUME condefs in
let predty = mk_fun_ty recty bool_ty in
let edefs = itlist (fun (x,l) acc -> map (fun t -> x,t) l @ acc) def [] in
let idefs = map2 (fun (r,(_,atys)) def -> (r,atys),def) edefs condefs in
let mk_rule ((r,a),condef) =
let left,right = dest_eq condef in
let args,bod = strip_abs right in
let lapp = list_mk_comb(left,args) in
let conds = itlist2
(fun arg argty sofar ->
if mem argty newtys then
mk_comb(mk_var(dest_vartype argty,predty),arg)::sofar
else sofar) args a [] in
let conc = mk_comb(mk_var(dest_vartype r,predty),lapp) in
let rule = if conds = [] then conc
else mk_imp(list_mk_conj conds,conc) in
list_mk_forall(args,rule) in
let rules = list_mk_conj (map mk_rule idefs) in
let th0 = derive_nonschematic_inductive_relations rules in
let th1 = prove_monotonicity_hyps th0 in
let th2a,th2bc = CONJ_PAIR th1 in
let th2b = CONJUNCT1 th2bc in
conths,th2a,th2b in
(* ----------------------------------------------------------------------- *)
(* Shows that the predicates defined by the rules are all nonempty. *)
(* (This could be done much more efficiently/cleverly, but it's OK.) *)
(* ----------------------------------------------------------------------- *)
let prove_model_inhabitation rth =
let srules = map SPEC_ALL (CONJUNCTS rth) in
let imps,bases = partition (is_imp o concl) srules in
let concs = map concl bases @ map (rand o concl) imps in
let preds = setify (map (repeat rator) concs) in
let rec exhaust_inhabitations ths sofar =
let dunnit = setify(map (fst o strip_comb o concl) sofar) in
let useful = filter
(fun th -> not (mem (fst(strip_comb(rand(concl th)))) dunnit)) ths in
if useful = [] then sofar else
let follow_horn thm =
let preds = map (fst o strip_comb) (conjuncts(lhand(concl thm))) in
let asms = map
(fun p -> find (fun th -> fst(strip_comb(concl th)) = p) sofar)
preds in
MATCH_MP thm (end_itlist CONJ asms) in
let newth = tryfind follow_horn useful in
exhaust_inhabitations ths (newth::sofar) in
let ithms = exhaust_inhabitations imps bases in
let exths = map
(fun p -> find (fun th -> fst(strip_comb(concl th)) = p) ithms) preds in
exths in
(* ----------------------------------------------------------------------- *)
(* Makes a type definition for one of the defined subsets. *)
(* ----------------------------------------------------------------------- *)
let define_inductive_type cdefs exth =
let extm = concl exth in
let epred = fst(strip_comb extm) in
let ename = fst(dest_var epred) in
let th1 = ASSUME (find (fun eq -> lhand eq = epred) (hyp exth)) in
let th2 = TRANS th1 (SUBS_CONV cdefs (rand(concl th1))) in
let th3 = EQ_MP (AP_THM th2 (rand extm)) exth in
let th4,_ = itlist SCRUB_EQUATION (hyp th3) (th3,[]) in
let mkname = "_mk_"^ename and destname = "_dest_"^ename in
let bij1,bij2 = new_basic_type_definition ename (mkname,destname) th4 in
let bij2a = AP_THM th2 (rand(rand(concl bij2))) in
let bij2b = TRANS bij2a bij2 in
bij1,bij2b in
(* ----------------------------------------------------------------------- *)
(* Defines a type constructor corresponding to current pseudo-constructor. *)
(* ----------------------------------------------------------------------- *)
let define_inductive_type_constructor defs consindex th =
let avs,bod = strip_forall(concl th) in
let asms,conc =
if is_imp bod then conjuncts(lhand bod),rand bod else [],bod in
let asmlist = map dest_comb asms in
let cpred,cterm = dest_comb conc in
let oldcon,oldargs = strip_comb cterm in
let modify_arg v =
try let dest = snd(assoc (rev_assoc v asmlist) consindex) in
let ty' = hd(snd(dest_type(type_of dest))) in
let v' = mk_var(fst(dest_var v),ty') in
mk_comb(dest,v'),v'
with Failure _ -> v,v in
let newrights,newargs = unzip(map modify_arg oldargs) in
let retmk = fst(assoc cpred consindex) in
let defbod = mk_comb(retmk,list_mk_comb(oldcon,newrights)) in
let defrt = list_mk_abs(newargs,defbod) in
let expth = find (fun th -> lhand(concl th) = oldcon) defs in
let rexpth = SUBS_CONV [expth] defrt in
let deflf = mk_var(fst(dest_var oldcon),type_of defrt) in
let defth = new_definition(mk_eq(deflf,rand(concl rexpth))) in
TRANS defth (SYM rexpth) in
(* ----------------------------------------------------------------------- *)
(* Instantiate the induction theorem on the representatives to transfer *)
(* it to the new type(s). Uses "\x. rep-pred(x) /\ P(mk x)" for "P". *)
(* ----------------------------------------------------------------------- *)
let instantiate_induction_theorem consindex ith =
let avs,bod = strip_forall(concl ith) in
let corlist = map((repeat rator F_F repeat rator) o dest_imp o body o rand)
(conjuncts(rand bod)) in
let consindex' = map (fun v -> let w = rev_assoc v corlist in
w,assoc w consindex) avs in
let recty = (hd o snd o dest_type o type_of o fst o snd o hd) consindex in
let newtys = map (hd o snd o dest_type o type_of o snd o snd) consindex' in
let ptypes = map (C mk_fun_ty bool_ty) newtys in
let preds = make_args "P" [] ptypes in
let args = make_args "x" [] (map (K recty) preds) in
let lambs = map2 (fun (r,(m,d)) (p,a) ->
mk_abs(a,mk_conj(mk_comb(r,a),mk_comb(p,mk_comb(m,a)))))
consindex' (zip preds args) in
SPECL lambs ith in
(* ----------------------------------------------------------------------- *)
(* Reduce a single clause of the postulated induction theorem (old_ver) ba *)
(* to the kind wanted for the new type (new_ver); |- new_ver ==> old_ver *)
(* ----------------------------------------------------------------------- *)
let pullback_induction_clause tybijpairs conthms =
let PRERULE = GEN_REWRITE_RULE (funpow 3 RAND_CONV) (map SYM conthms) in
let IPRULE = SYM o GEN_REWRITE_RULE I (map snd tybijpairs) in
fun rthm tm ->
let avs,bimp = strip_forall tm in
if is_imp bimp then
let ant,con = dest_imp bimp in
let ths = map (CONV_RULE BETA_CONV) (CONJUNCTS (ASSUME ant)) in
let tths,pths = unzip (map CONJ_PAIR ths) in
let tth = MATCH_MP (SPEC_ALL rthm) (end_itlist CONJ tths) in
let mths = map IPRULE (tth::tths) in
let conth1 = BETA_CONV con in
let contm1 = rand(concl conth1) in
let conth2 = TRANS conth1
(AP_TERM (rator contm1) (SUBS_CONV (tl mths) (rand contm1))) in
let conth3 = PRERULE conth2 in
let lctms = map concl pths in
let asmin = mk_imp(list_mk_conj lctms,rand(rand(concl conth3))) in
let argsin = map rand (conjuncts(lhand asmin)) in
let argsgen =
map (fun tm -> mk_var(fst(dest_var(rand tm)),type_of tm)) argsin in
let asmgen = subst (zip argsgen argsin) asmin in
let asmquant =
list_mk_forall(snd(strip_comb(rand(rand asmgen))),asmgen) in
let th1 = INST (zip argsin argsgen) (SPEC_ALL (ASSUME asmquant)) in
let th2 = MP th1 (end_itlist CONJ pths) in
let th3 = EQ_MP (SYM conth3) (CONJ tth th2) in
DISCH asmquant (GENL avs (DISCH ant th3))
else
let con = bimp in
let conth2 = BETA_CONV con in
let tth = PART_MATCH I rthm (lhand(rand(concl conth2))) in
let conth3 = PRERULE conth2 in
let asmgen = rand(rand(concl conth3)) in
let asmquant = list_mk_forall(snd(strip_comb(rand asmgen)),asmgen) in
let th2 = SPEC_ALL (ASSUME asmquant) in
let th3 = EQ_MP (SYM conth3) (CONJ tth th2) in
DISCH asmquant (GENL avs th3) in
(* ----------------------------------------------------------------------- *)
(* Finish off a consequence of the induction theorem. *)
(* ----------------------------------------------------------------------- *)
let finish_induction_conclusion consindex tybijpairs =
let tybij1,tybij2 = unzip tybijpairs in
let PRERULE =
GEN_REWRITE_RULE (LAND_CONV o LAND_CONV o RAND_CONV) tybij1 o
GEN_REWRITE_RULE LAND_CONV tybij2
and FINRULE = GEN_REWRITE_RULE RAND_CONV tybij1 in
fun th ->
let av,bimp = dest_forall(concl th) in
let pv = lhand(body(rator(rand bimp))) in
let p,v = dest_comb pv in
let mk,dest = assoc p consindex in
let ty = hd(snd(dest_type(type_of dest))) in
let v' = mk_var(fst(dest_var v),ty) in
let dv = mk_comb(dest,v') in
let th1 = PRERULE (SPEC dv th) in
let th2 = MP th1 (REFL (rand(lhand(concl th1)))) in
let th3 = CONV_RULE BETA_CONV th2 in
GEN v' (FINRULE (CONJUNCT2 th3)) in
(* ----------------------------------------------------------------------- *)
(* Derive the induction theorem. *)
(* ----------------------------------------------------------------------- *)
let derive_induction_theorem consindex tybijpairs conthms iith rth =
let bths = map2
(pullback_induction_clause tybijpairs conthms)
(CONJUNCTS rth) (conjuncts(lhand(concl iith))) in
let asm = list_mk_conj(map (lhand o concl) bths) in
let ths = map2 MP bths (CONJUNCTS (ASSUME asm)) in
let th1 = MP iith (end_itlist CONJ ths) in
let th2 = end_itlist CONJ (map
(finish_induction_conclusion consindex tybijpairs) (CONJUNCTS th1)) in
let th3 = DISCH asm th2 in
let preds = map (rator o body o rand) (conjuncts(rand(concl th3))) in
let th4 = GENL preds th3 in
let pasms = filter (C mem (map fst consindex) o lhand) (hyp th4) in
let th5 = itlist DISCH pasms th4 in
let th6,_ = itlist SCRUB_EQUATION (hyp th5) (th5,[]) in
let th7 = UNDISCH_ALL th6 in
fst (itlist SCRUB_EQUATION (hyp th7) (th7,[])) in
(* ----------------------------------------------------------------------- *)
(* Create the recursive functions and eliminate pseudo-constructors. *)
(* (These are kept just long enough to derive the key property.) *)
(* ----------------------------------------------------------------------- *)
let create_recursive_functions tybijpairs consindex conthms rth =
let domtys = map (hd o snd o dest_type o type_of o snd o snd) consindex in
let recty = (hd o snd o dest_type o type_of o fst o snd o hd) consindex in
let ranty = mk_vartype "Z" in
let fn = mk_var("fn",mk_fun_ty recty ranty)
and fns = make_args "fn" [] (map (C mk_fun_ty ranty) domtys) in
let args = make_args "a" [] domtys in
let rights = map2 (fun (_,(_,d)) a -> mk_abs(a,mk_comb(fn,mk_comb(d,a))))
consindex args in
let eqs = map2 (curry mk_eq) fns rights in
let fdefs = map ASSUME eqs in
let fxths1 = map (fun th1 -> tryfind (fun th2 -> MK_COMB(th2,th1)) fdefs)
conthms in
let fxths2 = map (fun th -> TRANS th (BETA_CONV (rand(concl th)))) fxths1 in
let mk_tybijcons (th1,th2) =
let th3 = INST [rand(lhand(concl th1)),rand(lhand(concl th2))] th2 in
let th4 = AP_TERM (rator(lhand(rand(concl th2)))) th1 in
EQ_MP (SYM th3) th4 in
let SCONV = GEN_REWRITE_CONV I (map mk_tybijcons tybijpairs)
and ERULE = GEN_REWRITE_RULE I (map snd tybijpairs) in
let simplify_fxthm rthm fxth =
let pat = funpow 4 rand (concl fxth) in
if is_imp(repeat (snd o dest_forall) (concl rthm)) then
let th1 = PART_MATCH (rand o rand) rthm pat in
let tms1 = conjuncts(lhand(concl th1)) in
let ths2 = map (fun t -> EQ_MP (SYM(SCONV t)) TRUTH) tms1 in
ERULE (MP th1 (end_itlist CONJ ths2))
else
ERULE (PART_MATCH rand rthm pat) in
let fxths3 = map2 simplify_fxthm (CONJUNCTS rth) fxths2 in
let fxths4 = map2 (fun th1 -> TRANS th1 o AP_TERM fn) fxths2 fxths3 in
let cleanup_fxthm cth fxth =
let tms = snd(strip_comb(rand(rand(concl fxth)))) in
let kth = RIGHT_BETAS tms (ASSUME (hd(hyp cth))) in
TRANS fxth (AP_TERM fn kth) in
let fxth5 = end_itlist CONJ (map2 cleanup_fxthm conthms fxths4) in
let pasms = filter (C mem (map fst consindex) o lhand) (hyp fxth5) in
let fxth6 = itlist DISCH pasms fxth5 in
let fxth7,_ =
itlist SCRUB_EQUATION (itlist (union o hyp) conthms []) (fxth6,[]) in
let fxth8 = UNDISCH_ALL fxth7 in
fst (itlist SCRUB_EQUATION (subtract (hyp fxth8) eqs) (fxth8,[])) in
(* ----------------------------------------------------------------------- *)
(* Create a function for recursion clause. *)
(* ----------------------------------------------------------------------- *)
let create_recursion_iso_constructor =
let s = `s:num->Z` in
let zty = `:Z` in
let numty = `:num` in
let rec extract_arg tup v =
if v = tup then REFL tup else
let t1,t2 = dest_pair tup in
let PAIR_th = ISPECL [t1;t2] (if free_in v t1 then FST else SND) in
let tup' = rand(concl PAIR_th) in
if tup' = v then PAIR_th else
let th = extract_arg (rand(concl PAIR_th)) v in
SUBS[SYM PAIR_th] th in
fun consindex ->
let recty = hd(snd(dest_type(type_of(fst(hd consindex))))) in
let domty = hd(snd(dest_type recty)) in
let i = mk_var("i",domty)
and r = mk_var("r",mk_fun_ty numty recty) in
let mks = map (fst o snd) consindex in
let mkindex = map (fun t -> hd(tl(snd(dest_type(type_of t)))),t) mks in
fun cth ->
let artms = snd(strip_comb(rand(rand(concl cth)))) in
let artys = mapfilter (type_of o rand) artms in
let args,bod = strip_abs(rand(hd(hyp cth))) in
let ccitm,rtm = dest_comb bod in
let cctm,itm = dest_comb ccitm in
let rargs,iargs = partition (C free_in rtm) args in
let xths = map (extract_arg itm) iargs in
let cargs' = map (subst [i,itm] o lhand o concl) xths in
let indices = map sucivate (0--(length rargs - 1)) in
let rindexed = map (curry mk_comb r) indices in
let rargs' = map2 (fun a rx -> mk_comb(assoc a mkindex,rx))
artys rindexed in
let sargs' = map (curry mk_comb s) indices in
let allargs = cargs'@ rargs' @ sargs' in
let funty = itlist (mk_fun_ty o type_of) allargs zty in
let funname = fst(dest_const(repeat rator (lhand(concl cth))))^"'" in
let funarg = mk_var(funname,funty) in
list_mk_abs([i;r;s],list_mk_comb(funarg,allargs)) in
(* ----------------------------------------------------------------------- *)
(* Derive the recursion theorem. *)
(* ----------------------------------------------------------------------- *)
let derive_recursion_theorem =
let CCONV = funpow 3 RATOR_CONV (REPEATC (GEN_REWRITE_CONV I [FCONS])) in
fun tybijpairs consindex conthms rath ->
let isocons = map (create_recursion_iso_constructor consindex) conthms in
let ty = type_of(hd isocons) in
let fcons = mk_const("FCONS",[ty,aty])
and fnil = mk_const("FNIL",[ty,aty]) in
let bigfun = itlist (mk_binop fcons) isocons fnil in
let eth = ISPEC bigfun CONSTR_REC in
let fn = rator(rand(hd(conjuncts(concl rath)))) in
let betm = let v,bod = dest_abs(rand(concl eth)) in vsubst[fn,v] bod in
let LCONV = REWR_CONV (ASSUME betm) in
let fnths =
map (fun t -> RIGHT_BETAS [bndvar(rand t)] (ASSUME t)) (hyp rath) in
let SIMPER = PURE_REWRITE_RULE
(map SYM fnths @ map fst tybijpairs @ [FST; SND; FCONS; BETA_THM]) in
let hackdown_rath th =
let ltm,rtm = dest_eq(concl th) in
let wargs = snd(strip_comb(rand ltm)) in
let th1 = TRANS th (LCONV rtm) in
let th2 = TRANS th1 (CCONV (rand(concl th1))) in
let th3 = TRANS th2 (funpow 2 RATOR_CONV BETA_CONV (rand(concl th2))) in
let th4 = TRANS th3 (RATOR_CONV BETA_CONV (rand(concl th3))) in
let th5 = TRANS th4 (BETA_CONV (rand(concl th4))) in
GENL wargs (SIMPER th5) in
let rthm = end_itlist CONJ (map hackdown_rath (CONJUNCTS rath)) in
let seqs =
let unseqs = filter is_eq (hyp rthm) in
let tys = map (hd o snd o dest_type o type_of o snd o snd) consindex in
map (fun ty -> find
(fun t -> hd(snd(dest_type(type_of(lhand t)))) = ty) unseqs) tys in
let rethm = itlist EXISTS_EQUATION seqs rthm in
let fethm = CHOOSE(fn,eth) rethm in
let pcons = map (repeat rator o rand o repeat (snd o dest_forall))
(conjuncts(concl rthm)) in
GENL pcons fethm in
(* ----------------------------------------------------------------------- *)
(* Basic function: returns induction and recursion separately. No parser. *)
(* ----------------------------------------------------------------------- *)
fun def ->
let defs,rth,ith = justify_inductive_type_model def in
let neths = prove_model_inhabitation rth in
let tybijpairs = map (define_inductive_type defs) neths in
let preds = map (repeat rator o concl) neths in
let mkdests = map
(fun (th,_) -> let tm = lhand(concl th) in rator tm,rator(rand tm))
tybijpairs in
let consindex = zip preds mkdests in
let condefs = map (define_inductive_type_constructor defs consindex)
(CONJUNCTS rth) in
let conthms = map
(fun th -> let args = fst(strip_abs(rand(concl th))) in
RIGHT_BETAS args th) condefs in
let iith = instantiate_induction_theorem consindex ith in
let fth = derive_induction_theorem consindex tybijpairs conthms iith rth in
let rath = create_recursive_functions tybijpairs consindex conthms rth in
let kth = derive_recursion_theorem tybijpairs consindex conthms rath in
fth,kth;;
(* ------------------------------------------------------------------------- *)
(* Parser to present a nice interface a la Melham. *)
(* ------------------------------------------------------------------------- *)
let parse_inductive_type_specification =
let parse_type_loc src =
let pty,rst = parse_pretype src in
type_of_pretype pty,rst in
let parse_type_conapp src =
let cn,sps =
match src with (Ident cn)::sps -> cn,sps
| _ -> fail() in
let tys,rst = many parse_type_loc sps in
(cn,tys),rst in
let parse_type_clause src =
let tn,sps =
match src with (Ident tn)::sps -> tn,sps
| _ -> fail() in
let tys,rst = (a (Ident "=") ++ listof parse_type_conapp (a (Resword "|"))
"type definition clauses"
>> snd) sps in
(mk_vartype tn,tys),rst in
let parse_type_definition =
listof parse_type_clause (a (Resword ";")) "type definition" in
fun s ->
let spec,rst = (parse_type_definition o lex o explode) s in
if rst = [] then spec
else failwith "parse_inductive_type_specification: junk after def";;
(* ------------------------------------------------------------------------- *)
(* Use this temporary version to define the sum type. *)
(* ------------------------------------------------------------------------- *)
let sum_INDUCT,sum_RECURSION =
define_type_raw (parse_inductive_type_specification "sum = INL A | INR B");;
let OUTL = new_recursive_definition sum_RECURSION
`OUTL (INL x :A+B) = x`;;
let OUTR = new_recursive_definition sum_RECURSION
`OUTR (INR y :A+B) = y`;;
(* ------------------------------------------------------------------------- *)
(* Generalize the recursion theorem to multiple domain types. *)
(* (We needed to use a single type to justify it via a proforma theorem.) *)
(* *)
(* NB! Before this is called nontrivially (i.e. more than one new type) *)
(* the type constructor ":sum", used internally, must have been defined. *)
(* ------------------------------------------------------------------------- *)
let define_type_raw =
let generalize_recursion_theorem =
let ELIM_OUTCOMBS = GEN_REWRITE_RULE TOP_DEPTH_CONV [OUTL; OUTR] in
let rec mk_sum tys =
let k = length tys in
if k = 1 then hd tys else
let tys1,tys2 = chop_list (k / 2) tys in
mk_type("sum",[mk_sum tys1; mk_sum tys2]) in
let mk_inls =
let rec mk_inls ty =
if is_vartype ty then [mk_var("x",ty)] else
let _,[ty1;ty2] = dest_type ty in
let inls1 = mk_inls ty1
and inls2 = mk_inls ty2 in
let inl = mk_const("INL",[ty1,aty; ty2,bty])
and inr = mk_const("INR",[ty1,aty; ty2,bty]) in
map (curry mk_comb inl) inls1 @ map (curry mk_comb inr) inls2 in
fun ty -> let bods = mk_inls ty in
map (fun t -> mk_abs(find_term is_var t,t)) bods in
let mk_outls =
let rec mk_inls sof ty =
if is_vartype ty then [sof] else
let _,[ty1;ty2] = dest_type ty in
let outl = mk_const("OUTL",[ty1,aty; ty2,bty])
and outr = mk_const("OUTR",[ty1,aty; ty2,bty]) in
mk_inls (mk_comb(outl,sof)) ty1 @ mk_inls (mk_comb(outr,sof)) ty2 in
fun ty -> let x = mk_var("x",ty) in
map (curry mk_abs x) (mk_inls x ty) in
let mk_newfun fn outl =
let s,ty = dest_var fn in
let dty = hd(snd(dest_type ty)) in
let x = mk_var("x",dty) in
let y,bod = dest_abs outl in
let r = mk_abs(x,vsubst[mk_comb(fn,x),y] bod) in
let l = mk_var(s,type_of r) in
let th1 = ASSUME (mk_eq(l,r)) in
RIGHT_BETAS [x] th1 in
fun th ->
let avs,ebod = strip_forall(concl th) in
let evs,bod = strip_exists ebod in
let n = length evs in
if n = 1 then th else
let tys = map (fun i -> mk_vartype ("Z"^(string_of_int i)))
(0--(n - 1)) in
let sty = mk_sum tys in
let inls = mk_inls sty
and outls = mk_outls sty in
let zty = type_of(rand(snd(strip_forall(hd(conjuncts bod))))) in
let ith = INST_TYPE [sty,zty] th in
let avs,ebod = strip_forall(concl ith) in
let evs,bod = strip_exists ebod in
let fns' = map2 mk_newfun evs outls in
let fnalist = zip evs (map (rator o lhs o concl) fns')
and inlalist = zip evs inls
and outlalist = zip evs outls in
let hack_clause tm =
let avs,bod = strip_forall tm in
let l,r = dest_eq bod in
let fn,args = strip_comb r in
let pargs = map
(fun a -> let g = genvar(type_of a) in
if is_var a then g,g else
let outl = assoc (rator a) outlalist in
mk_comb(outl,g),g) args in
let args',args'' = unzip pargs in
let inl = assoc (rator l) inlalist in
let rty = hd(snd(dest_type(type_of inl))) in
let nty = itlist (mk_fun_ty o type_of) args' rty in
let fn' = mk_var(fst(dest_var fn),nty) in
let r' = list_mk_abs(args'',mk_comb(inl,list_mk_comb(fn',args'))) in
r',fn in
let defs = map hack_clause (conjuncts bod) in
let jth = BETA_RULE (SPECL (map fst defs) ith) in
let bth = ASSUME (snd(strip_exists(concl jth))) in
let finish_clause th =
let avs,bod = strip_forall (concl th) in
let outl = assoc (rator (lhand bod)) outlalist in
GENL avs (BETA_RULE (AP_TERM outl (SPECL avs th))) in
let cth = end_itlist CONJ (map finish_clause (CONJUNCTS bth)) in
let dth = ELIM_OUTCOMBS cth in
let eth = GEN_REWRITE_RULE ONCE_DEPTH_CONV (map SYM fns') dth in
let fth = itlist SIMPLE_EXISTS (map snd fnalist) eth in
let dtms = map (hd o hyp) fns' in
let gth = itlist (fun e th -> let l,r = dest_eq e in
MP (INST [r,l] (DISCH e th)) (REFL r)) dtms fth in
let hth = PROVE_HYP jth (itlist SIMPLE_CHOOSE evs gth) in
let xvs = map (fst o strip_comb o rand o snd o strip_forall)
(conjuncts(concl eth)) in
GENL xvs hth in
fun def -> let ith,rth = define_type_raw def in
ith,generalize_recursion_theorem rth;;
(* ------------------------------------------------------------------------- *)
(* Set up options and lists. *)
(* ------------------------------------------------------------------------- *)
let option_INDUCT,option_RECURSION =
define_type_raw
(parse_inductive_type_specification "option = NONE | SOME A");;
let list_INDUCT,list_RECURSION =
define_type_raw
(parse_inductive_type_specification "list = NIL | CONS A list");;
(* ------------------------------------------------------------------------- *)
(* Tools for proving injectivity and distinctness of constructors. *)
(* ------------------------------------------------------------------------- *)
let prove_constructors_injective =
let DEPAIR = GEN_REWRITE_RULE TOP_SWEEP_CONV [PAIR_EQ] in
let prove_distinctness ax pat =
let f,args = strip_comb pat in
let rt = end_itlist (curry mk_pair) args in
let ty = mk_fun_ty (type_of pat) (type_of rt) in
let fn = genvar ty in
let dtm = mk_eq(mk_comb(fn,pat),rt) in
let eth = prove_recursive_functions_exist ax (list_mk_forall(args,dtm)) in
let args' = variants args args in
let atm = mk_eq(pat,list_mk_comb(f,args')) in
let ath = ASSUME atm in
let bth = AP_TERM fn ath in
let cth1 = SPECL args (ASSUME(snd(dest_exists(concl eth)))) in
let cth2 = INST (zip args' args) cth1 in
let pth = TRANS (TRANS (SYM cth1) bth) cth2 in
let qth = DEPAIR pth in
let qtm = concl qth in
let rth = rev_itlist (C(curry MK_COMB)) (CONJUNCTS(ASSUME qtm)) (REFL f) in
let tth = IMP_ANTISYM_RULE (DISCH atm qth) (DISCH qtm rth) in
let uth = GENL args (GENL args' tth) in
PROVE_HYP eth (SIMPLE_CHOOSE fn uth) in
fun ax ->
let cls = conjuncts(snd(strip_exists(snd(strip_forall(concl ax))))) in
let pats = map (rand o lhand o snd o strip_forall) cls in
end_itlist CONJ (mapfilter (prove_distinctness ax) pats);;
let prove_constructors_distinct =
let num_ty = `:num` in
let rec allopairs f l m =
if l = [] then [] else
map (f (hd l)) (tl m) @ allopairs f (tl l) (tl m) in
let NEGATE = GEN_ALL o CONV_RULE (REWR_CONV (TAUT `a ==> F <=> ~a`)) in
let prove_distinct ax pat =
let nums = map mk_small_numeral (0--(length pat - 1)) in
let fn = genvar (mk_type("fun",[type_of(hd pat); num_ty])) in
let ls = map (curry mk_comb fn) pat in
let defs = map2 (fun l r -> list_mk_forall(frees (rand l),mk_eq(l,r)))
ls nums in
let eth = prove_recursive_functions_exist ax (list_mk_conj defs) in
let ev,bod = dest_exists(concl eth) in
let REWRITE = GEN_REWRITE_RULE ONCE_DEPTH_CONV (CONJUNCTS (ASSUME bod)) in
let pat' = map
(fun t -> let f,args = if is_numeral t then t,[] else strip_comb t in
list_mk_comb(f,variants args args)) pat in
let pairs = allopairs (curry mk_eq) pat pat' in
let nths = map (REWRITE o AP_TERM fn o ASSUME) pairs in
let fths = map2 (fun t th -> NEGATE (DISCH t (CONV_RULE NUM_EQ_CONV th)))
pairs nths in
CONJUNCTS(PROVE_HYP eth (SIMPLE_CHOOSE ev (end_itlist CONJ fths))) in
fun ax ->
let cls = conjuncts(snd(strip_exists(snd(strip_forall(concl ax))))) in
let lefts = map (dest_comb o lhand o snd o strip_forall) cls in
let fns = itlist (insert o fst) lefts [] in
let pats = map (fun f -> map snd (filter ((=)f o fst) lefts)) fns in
end_itlist CONJ
(end_itlist (@) (mapfilter (prove_distinct ax) pats));;
(* ------------------------------------------------------------------------- *)
(* Automatically prove the case analysis theorems. *)
(* ------------------------------------------------------------------------- *)
let prove_cases_thm =
let mk_exclauses x rpats =
let xts = map (fun t -> list_mk_exists(frees t,mk_eq(x,t))) rpats in
mk_abs(x,list_mk_disj xts) in
let prove_triv tm =
let evs,bod = strip_exists tm in
let l,r = dest_eq bod in
if l = r then REFL l else
let lf,largs = strip_comb l
and rf,rargs = strip_comb r in
if lf = rf then
let ths = map (ASSUME o mk_eq) (zip rargs largs) in
let th1 = rev_itlist (C (curry MK_COMB)) ths (REFL lf) in
itlist EXISTS_EQUATION (map concl ths) (SYM th1)
else failwith "prove_triv" in
let rec prove_disj tm =
if is_disj tm then
let l,r = dest_disj tm in
try DISJ1 (prove_triv l) r
with Failure _ -> DISJ2 l (prove_disj r)
else
prove_triv tm in
let prove_eclause tm =
let avs,bod = strip_forall tm in
let ctm = if is_imp bod then rand bod else bod in
let cth = prove_disj ctm in
let dth = if is_imp bod then DISCH (lhand bod) cth else cth in
GENL avs dth in
fun th ->
let avs,bod = strip_forall(concl th) in
let cls = map (snd o strip_forall) (conjuncts(lhand bod)) in
let pats = map (fun t -> if is_imp t then rand t else t) cls in
let spats = map dest_comb pats in
let preds = itlist (insert o fst) spats [] in
let rpatlist = map
(fun pr -> map snd (filter (fun (p,x) -> p = pr) spats)) preds in
let xs = make_args "x" (freesl pats) (map (type_of o hd) rpatlist) in
let xpreds = map2 mk_exclauses xs rpatlist in
let ith = BETA_RULE (INST (zip xpreds preds) (SPEC_ALL th)) in
let eclauses = conjuncts(fst(dest_imp(concl ith))) in
MP ith (end_itlist CONJ (map prove_eclause eclauses));;
(* ------------------------------------------------------------------------- *)
(* Now deal with nested recursion. Need a store of previous theorems. *)
(* ------------------------------------------------------------------------- *)
inductive_type_store :=
["list",(2,list_INDUCT,list_RECURSION);
"option",(2,option_INDUCT,option_RECURSION);
"sum",(2,sum_INDUCT,sum_RECURSION)] @
(!inductive_type_store);;
(* ------------------------------------------------------------------------- *)
(* Also add a cached rewrite of distinctness and injectivity theorems. Since *)
(* there can be quadratically many distinctness clauses, it would really be *)
(* preferable to have a conversion, but this seems OK up 100 constructors. *)
(* ------------------------------------------------------------------------- *)
let basic_rectype_net = ref empty_net;;
let distinctness_store = ref ["bool",TAUT `(T <=> F) <=> F`];;
let injectivity_store = ref [];;
let extend_rectype_net (tyname,(_,_,rth)) =
let ths1 = try [prove_constructors_distinct rth] with Failure _ -> []
and ths2 = try [prove_constructors_injective rth] with Failure _ -> [] in
let canon_thl = itlist (mk_rewrites false) (ths1 @ ths2) [] in
distinctness_store := map (fun th -> tyname,th) ths1 @ (!distinctness_store);
injectivity_store := map (fun th -> tyname,th) ths2 @ (!injectivity_store);
basic_rectype_net :=
itlist (net_of_thm true) canon_thl (!basic_rectype_net);;
do_list extend_rectype_net (!inductive_type_store);;
(* ------------------------------------------------------------------------- *)
(* Return distinctness and injectivity for a type by simple lookup. *)
(* ------------------------------------------------------------------------- *)
let distinctness ty = assoc ty (!distinctness_store);;
let injectivity ty = assoc ty (!injectivity_store);;
let cases ty =
if ty = "num" then num_CASES else
let _,ith,_ = assoc ty (!inductive_type_store) in prove_cases_thm ith;;
(* ------------------------------------------------------------------------- *)
(* Convenient definitions for type isomorphism. *)
(* ------------------------------------------------------------------------- *)
let ISO = new_definition
`ISO (f:A->B) (g:B->A) <=> (!x. f(g x) = x) /\ (!y. g(f y) = y)`;;
let ISO_REFL = prove
(`ISO (\x:A. x) (\x. x)`,
REWRITE_TAC[ISO]);;
let ISO_FUN = prove
(`ISO (f:A->A') f' /\ ISO (g:B->B') g'
==> ISO (\h a'. g(h(f' a'))) (\h a. g'(h(f a)))`,
REWRITE_TAC[ISO; FUN_EQ_THM] THEN MESON_TAC[]);;
let ISO_USAGE = prove
(`ISO f g
==> (!P. (!x. P x) <=> (!x. P(g x))) /\
(!P. (?x. P x) <=> (?x. P(g x))) /\
(!a b. (a = g b) <=> (f a = b))`,
REWRITE_TAC[ISO; FUN_EQ_THM] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Hence extend type definition to nested types. *)
(* ------------------------------------------------------------------------- *)
let define_type_raw =
(* ----------------------------------------------------------------------- *)
(* Dispose of trivial antecedent. *)
(* ----------------------------------------------------------------------- *)
let TRIV_ANTE_RULE =
let TRIV_IMP_CONV tm =
let avs,bod = strip_forall tm in
let bth =
if is_eq bod then REFL (rand bod) else
let ant,con = dest_imp bod in
let ith = SUBS_CONV (CONJUNCTS(ASSUME ant)) (lhs con) in
DISCH ant ith in
GENL avs bth in
fun th ->
let tm = concl th in
if is_imp tm then
let ant,con = dest_imp(concl th) in
let cjs = conjuncts ant in
let cths = map TRIV_IMP_CONV cjs in
MP th (end_itlist CONJ cths)
else th in
(* ----------------------------------------------------------------------- *)
(* Lift type bijections to "arbitrary" (well, free rec or function) type. *)
(* ----------------------------------------------------------------------- *)
let ISO_EXPAND_CONV = PURE_ONCE_REWRITE_CONV[ISO] in
let rec lift_type_bijections iths cty =
let itys = map (hd o snd o dest_type o type_of o lhand o concl) iths in
try assoc cty (zip itys iths) with Failure _ ->
if not (exists (C occurs_in cty) itys)
then INST_TYPE [cty,aty] ISO_REFL else
let tycon,isotys = dest_type cty in
if tycon = "fun"
then MATCH_MP ISO_FUN
(end_itlist CONJ (map (lift_type_bijections iths) isotys))
else failwith
("lift_type_bijections: Unexpected type operator \""^tycon^"\"") in
(* ----------------------------------------------------------------------- *)
(* Prove isomorphism of nested types where former is the smaller. *)
(* ----------------------------------------------------------------------- *)
let DE_EXISTENTIALIZE_RULE =
let pth = prove
(`(?) P ==> (c = (@)P) ==> P c`,
GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM ETA_AX] THEN
DISCH_TAC THEN DISCH_THEN SUBST1_TAC THEN
MATCH_MP_TAC SELECT_AX THEN POP_ASSUM ACCEPT_TAC) in
let USE_PTH = MATCH_MP pth in
let rec DE_EXISTENTIALIZE_RULE th =
if not (is_exists(concl th)) then [],th else
let th1 = USE_PTH th in
let v1 = rand(rand(concl th1)) in
let gv = genvar(type_of v1) in
let th2 = CONV_RULE BETA_CONV (UNDISCH (INST [gv,v1] th1)) in
let vs,th3 = DE_EXISTENTIALIZE_RULE th2 in
gv::vs,th3 in
DE_EXISTENTIALIZE_RULE in
let grab_type = type_of o rand o lhand o snd o strip_forall in
let clause_corresponds cl0 =
let f0,ctm0 = dest_comb (lhs cl0) in
let c0 = fst(dest_const(fst(strip_comb ctm0))) in
let dty0,rty0 = dest_fun_ty (type_of f0) in
fun cl1 ->
let f1,ctm1 = dest_comb (lhs cl1) in
let c1 = fst(dest_const(fst(strip_comb ctm1))) in
let dty1,rty1 = dest_fun_ty (type_of f1) in
c0 = c1 && dty0 = rty1 && rty0 = dty1 in
let prove_inductive_types_isomorphic n k (ith0,rth0) (ith1,rth1) =
let sth0 = SPEC_ALL rth0
and sth1 = SPEC_ALL rth1
and t_tm = concl TRUTH in
let pevs0,pbod0 = strip_exists (concl sth0)
and pevs1,pbod1 = strip_exists (concl sth1) in
let pcjs0,qcjs0 = chop_list k (conjuncts pbod0)
and pcjs1,qcjs1 = chop_list k (snd(chop_list n (conjuncts pbod1))) in
let tyal0 = setify (zip (map grab_type pcjs1) (map grab_type pcjs0)) in
let tyal1 = map (fun (a,b) -> (b,a)) tyal0 in
let tyins0 = map
(fun f -> let domty,ranty = dest_fun_ty (type_of f) in
tysubst tyal0 domty,ranty) pevs0
and tyins1 = map
(fun f -> let domty,ranty = dest_fun_ty (type_of f) in
tysubst tyal1 domty,ranty) pevs1 in
let tth0 = INST_TYPE tyins0 sth0
and tth1 = INST_TYPE tyins1 sth1 in
let evs0,bod0 = strip_exists(concl tth0)
and evs1,bod1 = strip_exists(concl tth1) in
let lcjs0,rcjs0 = chop_list k (map (snd o strip_forall) (conjuncts bod0))
and lcjs1,rcjsx = chop_list k (map (snd o strip_forall)
(snd(chop_list n (conjuncts bod1)))) in
let rcjs1 = map (fun t -> find (clause_corresponds t) rcjsx) rcjs0 in
let proc_clause tm0 tm1 =
let l0,r0 = dest_eq tm0
and l1,r1 = dest_eq tm1 in
let vc0,wargs0 = strip_comb r0 in
let con0,vargs0 = strip_comb(rand l0) in
let gargs0 = map (genvar o type_of) wargs0 in
let nestf0 = map (fun a -> can (find (fun t -> is_comb t && rand t = a))
wargs0) vargs0 in
let targs0 = map2 (fun a f ->
if f then find (fun t -> is_comb t && rand t = a) wargs0 else a)
vargs0 nestf0 in
let gvlist0 = zip wargs0 gargs0 in
let xargs = map (fun v -> assoc v gvlist0) targs0 in
let inst0 =
list_mk_abs(gargs0,list_mk_comb(fst(strip_comb(rand l1)),xargs)),vc0 in
let vc1,wargs1 = strip_comb r1 in
let con1,vargs1 = strip_comb(rand l1) in
let gargs1 = map (genvar o type_of) wargs1 in
let targs1 = map2
(fun a f -> if f then
find (fun t -> is_comb t && rand t = a) wargs1
else a) vargs1 nestf0 in
let gvlist1 = zip wargs1 gargs1 in
let xargs = map (fun v -> assoc v gvlist1) targs1 in
let inst1 =
list_mk_abs(gargs1,list_mk_comb(fst(strip_comb(rand l0)),xargs)),vc1 in
inst0,inst1 in
let insts0,insts1 = unzip (map2 proc_clause (lcjs0@rcjs0) (lcjs1@rcjs1)) in
let uth0 = BETA_RULE(INST insts0 tth0)
and uth1 = BETA_RULE(INST insts1 tth1) in
let efvs0,sth0 = DE_EXISTENTIALIZE_RULE uth0
and efvs1,sth1 = DE_EXISTENTIALIZE_RULE uth1 in
let efvs2 = map
(fun t1 -> find (fun t2 -> hd(tl(snd(dest_type(type_of t1)))) =
hd(snd(dest_type(type_of t2)))) efvs1) efvs0 in
let isotms = map2 (fun ff gg -> list_mk_icomb "ISO" [ff;gg]) efvs0 efvs2 in
let ctm = list_mk_conj isotms in
let cth1 = ISO_EXPAND_CONV ctm in
let ctm1 = rand(concl cth1) in
let cjs = conjuncts ctm1 in
let eee = map (fun n -> n mod 2 = 0) (0--(length cjs - 1)) in
let cjs1,cjs2 = partition fst (zip eee cjs) in
let ctm2 = mk_conj(list_mk_conj (map snd cjs1),
list_mk_conj (map snd cjs2)) in
let DETRIV_RULE = TRIV_ANTE_RULE o REWRITE_RULE[sth0;sth1] in
let jth0 =
let itha = SPEC_ALL ith0 in
let icjs = conjuncts(rand(concl itha)) in
let cinsts = map
(fun tm -> tryfind (fun vtm -> term_match [] vtm tm) icjs)
(conjuncts (rand ctm2)) in
let tvs = subtract (fst(strip_forall(concl ith0)))
(itlist (fun (_,x,_) -> union (map snd x)) cinsts []) in
let ctvs =
map (fun p -> let x = mk_var("x",hd(snd(dest_type(type_of p)))) in
mk_abs(x,t_tm),p) tvs in
DETRIV_RULE (INST ctvs (itlist INSTANTIATE cinsts itha))
and jth1 =
let itha = SPEC_ALL ith1 in
let icjs = conjuncts(rand(concl itha)) in
let cinsts = map
(fun tm -> tryfind (fun vtm -> term_match [] vtm tm) icjs)
(conjuncts (lhand ctm2)) in
let tvs = subtract (fst(strip_forall(concl ith1)))
(itlist (fun (_,x,_) -> union (map snd x)) cinsts []) in
let ctvs =
map (fun p -> let x = mk_var("x",hd(snd(dest_type(type_of p)))) in
mk_abs(x,t_tm),p) tvs in
DETRIV_RULE (INST ctvs (itlist INSTANTIATE cinsts itha)) in
let cths4 = map2 CONJ (CONJUNCTS jth0) (CONJUNCTS jth1) in
let cths5 = map (PURE_ONCE_REWRITE_RULE[GSYM ISO]) cths4 in
let cth6 = end_itlist CONJ cths5 in
cth6,CONJ sth0 sth1 in
(* ----------------------------------------------------------------------- *)
(* Define nested type by doing a 1-level unwinding. *)
(* ----------------------------------------------------------------------- *)
let SCRUB_ASSUMPTION th =
let hyps = hyp th in
let eqn = find (fun t -> let x = lhs t in
forall (fun u -> not (free_in x (rand u))) hyps)
hyps in
let l,r = dest_eq eqn in
MP (INST [r,l] (DISCH eqn th)) (REFL r) in
let define_type_basecase def =
let add_id s = fst(dest_var(genvar bool_ty)) in
let def' = map (I F_F (map (add_id F_F I))) def in
define_type_raw def' in
let SIMPLE_BETA_RULE = GSYM o PURE_REWRITE_RULE[BETA_THM; FUN_EQ_THM] in
let ISO_USAGE_RULE = MATCH_MP ISO_USAGE in
let SIMPLE_ISO_EXPAND_RULE = CONV_RULE(REWR_CONV ISO) in
let REWRITE_FUN_EQ_RULE =
let ths = itlist (mk_rewrites false) [FUN_EQ_THM] [] in
let net = itlist (net_of_thm false) ths (basic_net()) in
CONV_RULE o GENERAL_REWRITE_CONV true TOP_DEPTH_CONV net in
let is_nested vs ty =
not (is_vartype ty) && not (intersect (tyvars ty) vs = []) in
let rec modify_type alist ty =
try rev_assoc ty alist
with Failure _ -> try
let tycon,tyargs = dest_type ty in
mk_type(tycon,map (modify_type alist) tyargs)
with Failure _ -> ty in
let modify_item alist (s,l) =
s,map (modify_type alist) l in
let modify_clause alist (l,lis) =
l,map (modify_item alist) lis in
let recover_clause id tm =
let con,args = strip_comb tm in
fst(dest_const con)^id,map type_of args in
let rec create_auxiliary_clauses nty =
let id = fst(dest_var(genvar bool_ty)) in
let tycon,tyargs = dest_type nty in
let k,ith,rth = try assoc tycon (!inductive_type_store) with Failure _ ->
failwith ("Can't find definition for nested type: "^tycon) in
let evs,bod = strip_exists(snd(strip_forall(concl rth))) in
let cjs = map (lhand o snd o strip_forall) (conjuncts bod) in
let rtys = map (hd o snd o dest_type o type_of) evs in
let tyins = tryfind (fun vty -> type_match vty nty []) rtys in
let cjs' = map (inst tyins o rand) (fst(chop_list k cjs)) in
let mtys = itlist (insert o type_of) cjs' [] in
let pcons = map (fun ty -> filter (fun t -> type_of t = ty) cjs') mtys in
let cls' = zip mtys (map (map (recover_clause id)) pcons) in
let tyal = map (fun ty -> mk_vartype(fst(dest_type ty)^id),ty) mtys in
let cls'' = map (modify_type tyal F_F map (modify_item tyal)) cls' in
k,tyal,cls'',INST_TYPE tyins ith,INST_TYPE tyins rth in
let rec define_type_nested def =
let n = length(itlist (@) (map (map fst o snd) def) []) in
let newtys = map fst def in
let utys = unions (itlist (union o map snd o snd) def []) in
let rectys = filter (is_nested newtys) utys in
if rectys = [] then
let th1,th2 = define_type_basecase def in n,th1,th2 else
let nty = hd (sort (fun t1 t2 -> occurs_in t2 t1) rectys) in
let k,tyal,ncls,ith,rth = create_auxiliary_clauses nty in
let cls = map (modify_clause tyal) def @ ncls in
let _,ith1,rth1 = define_type_nested cls in
let xnewtys = map (hd o snd o dest_type o type_of)
(fst(strip_exists(snd(strip_forall(concl rth1))))) in
let xtyal = map (fun ty -> let s = dest_vartype ty in
find (fun t -> fst(dest_type t) = s) xnewtys,ty)
(map fst cls) in
let ith0 = INST_TYPE xtyal ith
and rth0 = INST_TYPE xtyal rth in
let isoth,rclauses =
prove_inductive_types_isomorphic n k (ith0,rth0) (ith1,rth1) in
let irth3 = CONJ ith1 rth1 in
let vtylist = itlist (insert o type_of) (variables(concl irth3)) [] in
let isoths = CONJUNCTS isoth in
let isotys = map (hd o snd o dest_type o type_of o lhand o concl) isoths in
let ctylist = filter
(fun ty -> exists (fun t -> occurs_in t ty) isotys) vtylist in
let atylist = itlist
(union o striplist dest_fun_ty) ctylist [] in
let isoths' = map (lift_type_bijections isoths)
(filter (fun ty -> exists (fun t -> occurs_in t ty) isotys) atylist) in
let cisoths = map (BETA_RULE o lift_type_bijections isoths')
ctylist in
let uisoths = map ISO_USAGE_RULE cisoths in
let visoths = map (ASSUME o concl) uisoths in
let irth4 = itlist PROVE_HYP uisoths (REWRITE_FUN_EQ_RULE visoths irth3) in
let irth5 = REWRITE_RULE
(rclauses :: map SIMPLE_ISO_EXPAND_RULE isoths') irth4 in
let irth6 = repeat SCRUB_ASSUMPTION irth5 in
let ncjs = filter (fun t -> exists (fun v -> not(is_var v))
(snd(strip_comb(rand(lhs(snd(strip_forall t)))))))
(conjuncts(snd(strip_exists
(snd(strip_forall(rand(concl irth6))))))) in
let mk_newcon tm =
let vs,bod = strip_forall tm in
let rdeb = rand(lhs bod) in
let rdef = list_mk_abs(vs,rdeb) in
let newname = fst(dest_var(genvar bool_ty)) in
let def = mk_eq(mk_var(newname,type_of rdef),rdef) in
let dth = new_definition def in
SIMPLE_BETA_RULE dth in
let dths = map mk_newcon ncjs in
let ith6,rth6 = CONJ_PAIR(PURE_REWRITE_RULE dths irth6) in
n,ith6,rth6 in
fun def ->
let newtys = map fst def in
let truecons = itlist (@) (map (map fst o snd) def) [] in
let (p,ith0,rth0) = define_type_nested def in
let avs,etm = strip_forall(concl rth0) in
let allcls = conjuncts(snd(strip_exists etm)) in
let relcls = fst(chop_list (length truecons) allcls) in
let gencons =
map (repeat rator o rand o lhand o snd o strip_forall) relcls in
let cdefs =
map2 (fun s r -> SYM(new_definition (mk_eq(mk_var(s,type_of r),r))))
truecons gencons in
let tavs = make_args "f" [] (map type_of avs) in
let ith1 = SUBS cdefs ith0
and rth1 = GENL tavs (SUBS cdefs (SPECL tavs rth0)) in
let retval = p,ith1,rth1 in
let newentries = map (fun s -> dest_vartype s,retval) newtys in
(inductive_type_store := newentries @ (!inductive_type_store);
do_list extend_rectype_net newentries; ith1,rth1);;
(* ----------------------------------------------------------------------- *)
(* The overall function, with rather crude string-based benignity. *)
(* ----------------------------------------------------------------------- *)
let the_inductive_types = ref
["list = NIL | CONS A list",(list_INDUCT,list_RECURSION);
"option = NONE | SOME A",(option_INDUCT,option_RECURSION);
"sum = INL A | INR B",(sum_INDUCT,sum_RECURSION)];;
let define_type s =
try let retval = assoc s (!the_inductive_types) in
(warn true "Benign redefinition of inductive type"; retval)
with Failure _ ->
let defspec = parse_inductive_type_specification s in
let newtypes = map fst defspec
and constructors = itlist ((@) o map fst) (map snd defspec) [] in
if not(length(setify newtypes) = length newtypes)
then failwith "define_type: multiple definitions of a type"
else if not(length(setify constructors) = length constructors)
then failwith "define_type: multiple instances of a constructor"
else if exists (can get_type_arity o dest_vartype) newtypes
then let t = find (can get_type_arity) (map dest_vartype newtypes) in
failwith("define_type: type :"^t^" already defined")
else if exists (can get_const_type) constructors
then let t = find (can get_const_type) constructors in
failwith("define_type: constant "^t^" already defined")
else
let retval = define_type_raw defspec in
the_inductive_types := (s,retval)::(!the_inductive_types); retval;;
(* ------------------------------------------------------------------------- *)
(* Unwinding, and application of patterns. Add easy cases to default net. *)
(* ------------------------------------------------------------------------- *)
let UNWIND_CONV,MATCH_CONV =
let pth_0 = prove
(`(if ?!x. x = a /\ p then @x. x = a /\ p else @x. F) =
(if p then a else @x. F)`,
BOOL_CASES_TAC `p:bool` THEN ASM_REWRITE_TAC[COND_ID] THEN
MESON_TAC[])
and pth_1 = prove
(`_MATCH x (_SEQPATTERN r s) =
(if ?y. r x y then _MATCH x r else _MATCH x s) /\
_FUNCTION (_SEQPATTERN r s) x =
(if ?y. r x y then _FUNCTION r x else _FUNCTION s x)`,
REWRITE_TAC[_MATCH; _SEQPATTERN; _FUNCTION] THEN
MESON_TAC[])
and pth_2 = prove
(`((?y. _UNGUARDED_PATTERN (GEQ s t) (GEQ u y)) <=> s = t) /\
((?y. _GUARDED_PATTERN (GEQ s t) p (GEQ u y)) <=> s = t /\ p)`,
REWRITE_TAC[_UNGUARDED_PATTERN; _GUARDED_PATTERN; GEQ_DEF] THEN
MESON_TAC[])
and pth_3 = prove
(`(_MATCH x (\y z. P y z) = if ?!z. P x z then @z. P x z else @x. F) /\
(_FUNCTION (\y z. P y z) x = if ?!z. P x z then @z. P x z else @x. F)`,
REWRITE_TAC[_MATCH; _FUNCTION])
and pth_4 = prove
(`(_UNGUARDED_PATTERN (GEQ s t) (GEQ u y) <=> y = u /\ s = t) /\
(_GUARDED_PATTERN (GEQ s t) p (GEQ u y) <=> y = u /\ s = t /\ p)`,
REWRITE_TAC[_UNGUARDED_PATTERN; _GUARDED_PATTERN; GEQ_DEF] THEN
MESON_TAC[])
and pth_5 = prove
(`(if ?!z. z = k then @z. z = k else @x. F) = k`,
MESON_TAC[]) in
let rec INSIDE_EXISTS_CONV conv tm =
if is_exists tm then BINDER_CONV (INSIDE_EXISTS_CONV conv) tm
else conv tm in
let PUSH_EXISTS_CONV =
let econv = REWR_CONV SWAP_EXISTS_THM in
let rec conv bc tm =
try (econv THENC BINDER_CONV(conv bc)) tm
with Failure _ -> bc tm in
conv in
let BREAK_CONS_CONV =
let conv2 = GEN_REWRITE_CONV DEPTH_CONV [AND_CLAUSES; OR_CLAUSES] THENC
ASSOC_CONV CONJ_ASSOC in
fun tm ->
let conv0 = TOP_SWEEP_CONV(REWRITES_CONV(!basic_rectype_net)) in
let conv1 = if is_conj tm then LAND_CONV conv0 else conv0 in
(conv1 THENC conv2) tm in
let UNWIND_CONV =
let baseconv = GEN_REWRITE_CONV I
[UNWIND_THM1; UNWIND_THM2;
EQT_INTRO(SPEC_ALL EXISTS_REFL);
EQT_INTRO(GSYM(SPEC_ALL EXISTS_REFL))] in
let rec UNWIND_CONV tm =
let evs,bod = strip_exists tm in
let eqs = conjuncts bod in
try let eq = find
(fun tm -> is_eq tm &
let l,r = dest_eq tm in
(mem l evs && not (free_in l r)) ||
(mem r evs && not (free_in r l))) eqs in
let l,r = dest_eq eq in
let v = if mem l evs && not (free_in l r) then l else r in
let cjs' = eq::(subtract eqs [eq]) in
let n = length evs - (1 + index v (rev evs)) in
let th1 = CONJ_ACI_RULE(mk_eq(bod,list_mk_conj cjs')) in
let th2 = itlist MK_EXISTS evs th1 in
let th3 = funpow n BINDER_CONV (PUSH_EXISTS_CONV baseconv)
(rand(concl th2)) in
CONV_RULE (RAND_CONV UNWIND_CONV) (TRANS th2 th3)
with Failure _ -> REFL tm in
UNWIND_CONV in
let MATCH_SEQPATTERN_CONV =
GEN_REWRITE_CONV I [pth_1] THENC
RATOR_CONV(LAND_CONV
(BINDER_CONV(RATOR_CONV BETA_CONV THENC BETA_CONV) THENC
PUSH_EXISTS_CONV(GEN_REWRITE_CONV I [pth_2] THENC BREAK_CONS_CONV) THENC
UNWIND_CONV THENC
GEN_REWRITE_CONV DEPTH_CONV
[EQT_INTRO(SPEC_ALL EQ_REFL); AND_CLAUSES] THENC
GEN_REWRITE_CONV DEPTH_CONV [EXISTS_SIMP]))
and MATCH_ONEPATTERN_CONV tm =
let th1 = GEN_REWRITE_CONV I [pth_3] tm in
let tm' = body(rand(lhand(rand(concl th1)))) in
let th2 = (INSIDE_EXISTS_CONV
(GEN_REWRITE_CONV I [pth_4] THENC
RAND_CONV BREAK_CONS_CONV) THENC
UNWIND_CONV THENC
GEN_REWRITE_CONV DEPTH_CONV
[EQT_INTRO(SPEC_ALL EQ_REFL); AND_CLAUSES] THENC
GEN_REWRITE_CONV DEPTH_CONV [EXISTS_SIMP])
tm' in
let conv tm = if tm = lhand(concl th2) then th2 else fail() in
CONV_RULE
(RAND_CONV (RATOR_CONV
(COMB2_CONV (RAND_CONV (BINDER_CONV conv)) (BINDER_CONV conv))))
th1 in
let MATCH_SEQPATTERN_CONV_TRIV =
MATCH_SEQPATTERN_CONV THENC
GEN_REWRITE_CONV I [COND_CLAUSES]
and MATCH_SEQPATTERN_CONV_GEN =
MATCH_SEQPATTERN_CONV THENC
GEN_REWRITE_CONV TRY_CONV [COND_CLAUSES]
and MATCH_ONEPATTERN_CONV_TRIV =
MATCH_ONEPATTERN_CONV THENC
GEN_REWRITE_CONV I [pth_5]
and MATCH_ONEPATTERN_CONV_GEN =
MATCH_ONEPATTERN_CONV THENC
GEN_REWRITE_CONV TRY_CONV [pth_0; pth_5] in
do_list extend_basic_convs
["MATCH_SEQPATTERN_CONV",
(`_MATCH x (_SEQPATTERN r s)`,MATCH_SEQPATTERN_CONV_TRIV);
"FUN_SEQPATTERN_CONV",
(`_FUNCTION (_SEQPATTERN r s) x`,MATCH_SEQPATTERN_CONV_TRIV);
"MATCH_ONEPATTERN_CONV",
(`_MATCH x (\y z. P y z)`,MATCH_ONEPATTERN_CONV_TRIV);
"FUN_ONEPATTERN_CONV",
(`_FUNCTION (\y z. P y z) x`,MATCH_ONEPATTERN_CONV_TRIV)];
(CHANGED_CONV UNWIND_CONV,
(MATCH_SEQPATTERN_CONV_GEN ORELSEC MATCH_ONEPATTERN_CONV_GEN));;
let FORALL_UNWIND_CONV =
let PUSH_FORALL_CONV =
let econv = REWR_CONV SWAP_FORALL_THM in
let rec conv bc tm =
try (econv THENC BINDER_CONV(conv bc)) tm
with Failure _ -> bc tm in
conv in
let baseconv = GEN_REWRITE_CONV I
[MESON[] `(!x. x = a /\ p x ==> q x) <=> (p a ==> q a)`;
MESON[] `(!x. a = x /\ p x ==> q x) <=> (p a ==> q a)`;
MESON[] `(!x. x = a ==> q x) <=> q a`;
MESON[] `(!x. a = x ==> q x) <=> q a`] in
let rec FORALL_UNWIND_CONV tm =
try let avs,bod = strip_forall tm in
let ant,con = dest_imp bod in
let eqs = conjuncts ant in
let eq = find (fun tm ->
is_eq tm &
let l,r = dest_eq tm in
(mem l avs && not (free_in l r)) ||
(mem r avs && not (free_in r l))) eqs in
let l,r = dest_eq eq in
let v = if mem l avs && not (free_in l r) then l else r in
let cjs' = eq::(subtract eqs [eq]) in
let n = length avs - (1 + index v (rev avs)) in
let th1 = CONJ_ACI_RULE(mk_eq(ant,list_mk_conj cjs')) in
let th2 = AP_THM (AP_TERM (rator(rator bod)) th1) con in
let th3 = itlist MK_FORALL avs th2 in
let th4 = funpow n BINDER_CONV (PUSH_FORALL_CONV baseconv)
(rand(concl th3)) in
CONV_RULE (RAND_CONV FORALL_UNWIND_CONV) (TRANS th3 th4)
with Failure _ -> REFL tm in
FORALL_UNWIND_CONV;;
|