16 [1] Clemens Ballarin. Locales and Locale Expressions in Isabelle/Isar. |
16 [1] Clemens Ballarin. Locales and Locale Expressions in Isabelle/Isar. |
17 In Stefano Berardi et al., Types for Proofs and Programs: International |
17 In Stefano Berardi et al., Types for Proofs and Programs: International |
18 Workshop, TYPES 2003, Torino, Italy, LNCS 3085, pages 34-50, 2004. |
18 Workshop, TYPES 2003, Torino, Italy, LNCS 3085, pages 34-50, 2004. |
19 *) |
19 *) |
20 |
20 |
|
21 (* TODO: |
|
22 - beta-eta normalisation of interpretation parameters |
|
23 - no beta reduction of interpretation witnesses |
|
24 - mix of locales with and without open in activate_elems |
|
25 - dangling type frees in locales |
|
26 *) |
|
27 |
21 signature LOCALE = |
28 signature LOCALE = |
22 sig |
29 sig |
23 type context |
30 type context |
24 datatype ('typ, 'term, 'fact) elem = |
31 datatype ('typ, 'term, 'fact) elem = |
25 Fixes of (string * 'typ option * mixfix option) list | |
32 Fixes of (string * 'typ option * mixfix option) list | |
|
33 Constrains of (string * 'typ) list | |
26 Assumes of ((string * Attrib.src list) * ('term * ('term list * 'term list)) list) list | |
34 Assumes of ((string * Attrib.src list) * ('term * ('term list * 'term list)) list) list | |
27 Defines of ((string * Attrib.src list) * ('term * 'term list)) list | |
35 Defines of ((string * Attrib.src list) * ('term * 'term list)) list | |
28 Notes of ((string * Attrib.src list) * ('fact * Attrib.src list) list) list |
36 Notes of ((string * Attrib.src list) * ('fact * Attrib.src list) list) list |
29 datatype expr = |
37 datatype expr = |
30 Locale of string | |
38 Locale of string | |
561 (* map elements *) |
568 (* map elements *) |
562 |
569 |
563 fun map_elem {name, var, typ, term, fact, attrib} = |
570 fun map_elem {name, var, typ, term, fact, attrib} = |
564 fn Fixes fixes => Fixes (fixes |> map (fn (x, T, mx) => |
571 fn Fixes fixes => Fixes (fixes |> map (fn (x, T, mx) => |
565 let val (x', mx') = var (x, mx) in (x', Option.map typ T, mx') end)) |
572 let val (x', mx') = var (x, mx) in (x', Option.map typ T, mx') end)) |
|
573 | Constrains csts => Constrains (csts |> map (fn (x, T) => |
|
574 let val (x', _) = var (x, SOME Syntax.NoSyn) in (x', typ T) end)) |
566 | Assumes asms => Assumes (asms |> map (fn ((a, atts), propps) => |
575 | Assumes asms => Assumes (asms |> map (fn ((a, atts), propps) => |
567 ((name a, map attrib atts), propps |> map (fn (t, (ps, qs)) => |
576 ((name a, map attrib atts), propps |> map (fn (t, (ps, qs)) => |
568 (term t, (map term ps, map term qs)))))) |
577 (term t, (map term ps, map term qs)))))) |
569 | Defines defs => Defines (defs |> map (fn ((a, atts), (t, ps)) => |
578 | Defines defs => Defines (defs |> map (fn ((a, atts), (t, ps)) => |
570 ((name a, map attrib atts), (term t, map term ps)))) |
579 ((name a, map attrib atts), (term t, map term ps)))) |
1122 fun declare_int_elem (ctxt, Fixes fixes) = |
1132 fun declare_int_elem (ctxt, Fixes fixes) = |
1123 (ctxt |> ProofContext.add_fixes (map (fn (x, T, mx) => |
1133 (ctxt |> ProofContext.add_fixes (map (fn (x, T, mx) => |
1124 (x, Option.map (Term.map_type_tfree (TypeInfer.param 0)) T, mx)) fixes), []) |
1134 (x, Option.map (Term.map_type_tfree (TypeInfer.param 0)) T, mx)) fixes), []) |
1125 | declare_int_elem (ctxt, _) = (ctxt, []); |
1135 | declare_int_elem (ctxt, _) = (ctxt, []); |
1126 |
1136 |
1127 fun declare_ext_elem prep_fixes (ctxt, Fixes fixes) = |
1137 fun declare_ext_elem prep_parms (ctxt, Fixes fixes) = |
1128 (ctxt |> ProofContext.add_fixes (prep_fixes ctxt fixes), []) |
1138 let |
|
1139 val parms = map (fn (x, T, _) => (x, T)) fixes; |
|
1140 val parms' = prep_parms ctxt parms; |
|
1141 val fixes' = map (fn ((x, T), (_, _, mx)) => (x, T, mx)) (parms' ~~ fixes); |
|
1142 in (ctxt |> ProofContext.add_fixes fixes', []) end |
|
1143 | declare_ext_elem prep_parms (ctxt, Constrains csts) = |
|
1144 let |
|
1145 val parms = map (fn (x, T) => (x, SOME T)) csts; |
|
1146 val parms' = prep_parms ctxt parms; |
|
1147 val ts = map (fn (x, SOME T) => Free (x, T)) parms'; |
|
1148 in (Library.fold ProofContext.declare_term ts ctxt, []) end |
1129 | declare_ext_elem _ (ctxt, Assumes asms) = (ctxt, map #2 asms) |
1149 | declare_ext_elem _ (ctxt, Assumes asms) = (ctxt, map #2 asms) |
1130 | declare_ext_elem _ (ctxt, Defines defs) = (ctxt, map (fn (_, (t, ps)) => [(t, (ps, []))]) defs) |
1150 | declare_ext_elem _ (ctxt, Defines defs) = (ctxt, map (fn (_, (t, ps)) => [(t, (ps, []))]) defs) |
1131 | declare_ext_elem _ (ctxt, Notes facts) = (ctxt, []); |
1151 | declare_ext_elem _ (ctxt, Notes facts) = (ctxt, []); |
1132 |
1152 |
1133 fun declare_elems prep_fixes (ctxt, (((name, ps), _), elems)) = |
1153 fun declare_elems prep_parms (ctxt, (((name, ps), _), elems)) = |
1134 let val (ctxt', propps) = |
1154 let val (ctxt', propps) = |
1135 (case elems of |
1155 (case elems of |
1136 Int es => foldl_map declare_int_elem (ctxt, es) |
1156 Int es => foldl_map declare_int_elem (ctxt, es) |
1137 | Ext e => foldl_map (declare_ext_elem prep_fixes) (ctxt, [e])) |
1157 | Ext e => foldl_map (declare_ext_elem prep_parms) (ctxt, [e])) |
1138 handle ProofContext.CONTEXT (msg, ctxt) => err_in_locale ctxt msg [(name, map fst ps)] |
1158 handle ProofContext.CONTEXT (msg, ctxt) => err_in_locale ctxt msg [(name, map fst ps)] |
1139 in (ctxt', propps) end; |
1159 in (ctxt', propps) end; |
1140 |
1160 |
1141 in |
1161 in |
1142 |
1162 |
1143 (* CB: only called by prep_elemss. *) |
1163 (* CB: only called by prep_elemss. *) |
1144 |
1164 |
1145 fun declare_elemss prep_fixes fixed_params raw_elemss ctxt = |
1165 fun declare_elemss prep_parms fixed_params raw_elemss ctxt = |
1146 let |
1166 let |
1147 (* CB: fix of type bug of goal in target with context elements. |
1167 (* CB: fix of type bug of goal in target with context elements. |
1148 Parameters new in context elements must receive types that are |
1168 Parameters new in context elements must receive types that are |
1149 distinct from types of parameters in target (fixed_params). *) |
1169 distinct from types of parameters in target (fixed_params). *) |
1150 val ctxt_with_fixed = |
1170 val ctxt_with_fixed = |
1268 |
1291 |
1269 end; |
1292 end; |
1270 |
1293 |
1271 (* CB: type inference and consistency checks for locales *) |
1294 (* CB: type inference and consistency checks for locales *) |
1272 |
1295 |
1273 fun prep_elemss prep_fixes prepp do_close context fixed_params raw_elemss raw_concl = |
1296 fun prep_elemss prep_parms prepp do_close context fixed_params raw_elemss raw_concl = |
1274 let |
1297 let |
1275 (* CB: contexts computed in the course of this function are discarded. |
1298 (* CB: contexts computed in the course of this function are discarded. |
1276 They are used for type inference and consistency checks only. *) |
1299 They are used for type inference and consistency checks only. *) |
1277 (* CB: fixed_params are the parameters (with types) of the target locale, |
1300 (* CB: fixed_params are the parameters (with types) of the target locale, |
1278 empty list if there is no target. *) |
1301 empty list if there is no target. *) |
1279 (* CB: raw_elemss are list of pairs consisting of identifiers and |
1302 (* CB: raw_elemss are list of pairs consisting of identifiers and |
1280 context elements, the latter marked as internal or external. *) |
1303 context elements, the latter marked as internal or external. *) |
1281 val (raw_ctxt, raw_proppss) = declare_elemss prep_fixes fixed_params raw_elemss context; |
1304 val (raw_ctxt, raw_proppss) = declare_elemss prep_parms fixed_params raw_elemss context; |
1282 (* CB: raw_ctxt is context with additional fixed variables derived from |
1305 (* CB: raw_ctxt is context with additional fixed variables derived from |
1283 the fixes elements in raw_elemss, |
1306 the fixes elements in raw_elemss, |
1284 raw_proppss contains assumptions and definitions from the |
1307 raw_proppss contains assumptions and definitions from the |
1285 external elements in raw_elemss. *) |
1308 external elements in raw_elemss. *) |
1286 val raw_propps = map List.concat raw_proppss; |
1309 val raw_propps = map List.concat raw_proppss; |
1309 (map (ProofContext.default_type ctxt) xs); |
1332 (map (ProofContext.default_type ctxt) xs); |
1310 val parms = param_types (xs ~~ typing); |
1333 val parms = param_types (xs ~~ typing); |
1311 (* CB: parms are the parameters from raw_elemss, with correct typing. *) |
1334 (* CB: parms are the parameters from raw_elemss, with correct typing. *) |
1312 |
1335 |
1313 (* CB: extract information from assumes and defines elements |
1336 (* CB: extract information from assumes and defines elements |
1314 (fixes and notes in raw_elemss don't have an effect on text and elemss), |
1337 (fixes, constrains and notes in raw_elemss don't have an effect on |
1315 compute final form of context elements. *) |
1338 text and elemss), compute final form of context elements. *) |
1316 val (text, elemss) = finish_elemss ctxt parms do_close |
1339 val (text, elemss) = finish_elemss ctxt parms do_close |
1317 (((([], []), ([], [])), ([], [], [])), raw_elemss ~~ proppss); |
1340 (((([], []), ([], [])), ([], [], [])), raw_elemss ~~ proppss); |
1318 (* CB: text has the following structure: |
1341 (* CB: text has the following structure: |
1319 (((exts, exts'), (ints, ints')), (xs, env, defs)) |
1342 (((exts, exts'), (ints, ints')), (xs, env, defs)) |
1320 where |
1343 where |
1440 val cert_context_statement = gen_statement (K I) gen_context_i; |
1463 val cert_context_statement = gen_statement (K I) gen_context_i; |
1441 |
1464 |
1442 end; |
1465 end; |
1443 |
1466 |
1444 |
1467 |
1445 (** CB: experimental instantiation mechanism **) |
|
1446 |
|
1447 fun instantiate loc_name (prfx, attribs) raw_inst ctxt = |
|
1448 let |
|
1449 val thy = ProofContext.theory_of ctxt; |
|
1450 val sign = Theory.sign_of thy; |
|
1451 val tsig = Sign.tsig_of sign; |
|
1452 val cert = cterm_of sign; |
|
1453 |
|
1454 (** process the locale **) |
|
1455 |
|
1456 val {predicate = (_, axioms), params = (ps, _), ...} = |
|
1457 the_locale thy (intern sign loc_name); |
|
1458 val fixed_params = param_types (map #1 ps); |
|
1459 val init = ProofContext.init thy; |
|
1460 val (_, raw_elemss) = flatten (init, intern_expr sign) |
|
1461 (([], Symtab.empty), Expr (Locale loc_name)); |
|
1462 val ((parms, all_elemss, concl), |
|
1463 (spec as (_, (ints, _)), (xs, env, defs))) = |
|
1464 read_elemss false (* do_close *) init |
|
1465 fixed_params (* could also put [] here??? *) raw_elemss |
|
1466 [] (* concl *); |
|
1467 |
|
1468 (** analyse the instantiation theorem inst **) |
|
1469 |
|
1470 val inst = case raw_inst of |
|
1471 NONE => if null ints |
|
1472 then NONE |
|
1473 else error "Locale has assumptions but no chained fact was found" |
|
1474 | SOME [] => if null ints |
|
1475 then NONE |
|
1476 else error "Locale has assumptions but no chained fact was found" |
|
1477 | SOME [thm] => if null ints |
|
1478 then (warning "Locale has no assumptions: fact ignored"; NONE) |
|
1479 else SOME thm |
|
1480 | SOME _ => error "Multiple facts are not allowed"; |
|
1481 |
|
1482 val args = case inst of |
|
1483 NONE => [] |
|
1484 | SOME thm => thm |> prop_of |> ObjectLogic.drop_judgment sign |
|
1485 |> Term.strip_comb |
|
1486 |>> (fn t as (Const (s, _)) => if (intern sign loc_name = s) |
|
1487 then t |
|
1488 else error ("Constant " ^ quote loc_name ^ |
|
1489 " expected but constant " ^ quote s ^ " was found") |
|
1490 | t => error ("Constant " ^ quote loc_name ^ " expected \ |
|
1491 \but term " ^ quote (Sign.string_of_term sign t) ^ |
|
1492 " was found")) |
|
1493 |> snd; |
|
1494 val cargs = map cert args; |
|
1495 |
|
1496 (* process parameters: match their types with those of arguments *) |
|
1497 |
|
1498 val def_names = map (fn (Free (s, _), _) => s) env; |
|
1499 val (defined, assumed) = List.partition |
|
1500 (fn (s, _) => s mem def_names) fixed_params; |
|
1501 val cassumed = map (cert o Free) assumed; |
|
1502 val cdefined = map (cert o Free) defined; |
|
1503 |
|
1504 val param_types = map snd assumed; |
|
1505 val v_param_types = map Type.varifyT param_types; |
|
1506 val arg_types = map Term.fastype_of args; |
|
1507 val Tenv = Library.foldl (Type.typ_match tsig) |
|
1508 (Vartab.empty, v_param_types ~~ arg_types) |
|
1509 handle UnequalLengths => error "Number of parameters does not \ |
|
1510 \match number of arguments of chained fact"; |
|
1511 (* get their sorts *) |
|
1512 val tfrees = foldr Term.add_typ_tfrees [] param_types |
|
1513 val Tenv' = map |
|
1514 (fn ((a, i), (S, T)) => ((a, S), T)) |
|
1515 (Vartab.dest Tenv); |
|
1516 |
|
1517 (* process (internal) elements *) |
|
1518 |
|
1519 fun inst_type [] T = T |
|
1520 | inst_type env T = |
|
1521 Term.map_type_tfree (fn v => getOpt (assoc (env, v), TFree v)) T; |
|
1522 |
|
1523 fun inst_term [] t = t |
|
1524 | inst_term env t = Term.map_term_types (inst_type env) t; |
|
1525 |
|
1526 (* parameters with argument types *) |
|
1527 |
|
1528 val cparams' = map (cterm_of sign o inst_term Tenv' o term_of) cassumed; |
|
1529 val cdefined' = map (cert o inst_term Tenv' o term_of) cdefined; |
|
1530 val cdefining = map (cert o inst_term Tenv' o snd) env; |
|
1531 |
|
1532 fun inst_thm _ [] th = th |
|
1533 | inst_thm ctxt Tenv th = |
|
1534 let |
|
1535 val sign = ProofContext.sign_of ctxt; |
|
1536 val cert = Thm.cterm_of sign; |
|
1537 val certT = Thm.ctyp_of sign; |
|
1538 val {hyps, prop, maxidx, ...} = Thm.rep_thm th; |
|
1539 val tfrees = foldr Term.add_term_tfree_names [] (prop :: hyps); |
|
1540 val Tenv' = List.filter (fn ((a, _), _) => a mem_string tfrees) Tenv; |
|
1541 in |
|
1542 if null Tenv' then th |
|
1543 else |
|
1544 th |
|
1545 |> Drule.implies_intr_list (map cert hyps) |
|
1546 |> Drule.tvars_intr_list (map (#1 o #1) Tenv') |
|
1547 |> (fn (th', al) => th' |> |
|
1548 Thm.instantiate ((map (fn ((a, _), T) => |
|
1549 (certT (TVar (valOf (assoc (al, a)))), certT T)) Tenv'), [])) |
|
1550 |> (fn th'' => Drule.implies_elim_list th'' |
|
1551 (map (Thm.assume o cert o inst_term Tenv') hyps)) |
|
1552 end; |
|
1553 |
|
1554 val inst_type' = inst_type Tenv'; |
|
1555 |
|
1556 val inst_term' = Term.subst_atomic |
|
1557 (map (pairself term_of) ((cparams' @ cdefined') ~~ (cargs @ cdefining))) |
|
1558 o inst_term Tenv'; |
|
1559 |
|
1560 fun inst_thm' thm = |
|
1561 let |
|
1562 (* not all axs are normally applicable *) |
|
1563 val hyps = #hyps (rep_thm thm); |
|
1564 val ass = map (fn ax => (prop_of ax, ax)) axioms; |
|
1565 val axs' = Library.foldl (fn (axs, hyp) => |
|
1566 (case gen_assoc (op aconv) (ass, hyp) of NONE => axs |
|
1567 | SOME ax => axs @ [ax])) ([], hyps); |
|
1568 val thm' = Drule.satisfy_hyps axs' thm; |
|
1569 (* instantiate types *) |
|
1570 val thm'' = inst_thm ctxt Tenv' thm'; |
|
1571 (* substitute arguments and discharge hypotheses *) |
|
1572 val thm''' = case inst of |
|
1573 NONE => thm'' |
|
1574 | SOME inst_thm => let |
|
1575 val hyps = #hyps (rep_thm thm''); |
|
1576 val th = thm'' |> implies_intr_hyps |
|
1577 |> forall_intr_list (cparams' @ cdefined') |
|
1578 |> forall_elim_list (cargs @ cdefining) |
|
1579 (* th has premises of the form either inst_thm or x==x *) |
|
1580 fun mk hyp = if Logic.is_equals hyp |
|
1581 then hyp |> Logic.dest_equals |> snd |> cert |
|
1582 |> reflexive |
|
1583 else inst_thm |
|
1584 in implies_elim_list th (map mk hyps) |
|
1585 end; |
|
1586 in thm''' end |
|
1587 handle THM (msg, n, thms) => error ("Exception THM " ^ |
|
1588 string_of_int n ^ " raised\n" ^ |
|
1589 "Note: instantiate does not support old-style locales \ |
|
1590 \declared with (open)\n" ^ msg ^ "\n" ^ |
|
1591 cat_lines (map string_of_thm thms)); |
|
1592 |
|
1593 fun inst_elem (ctxt, (Ext _)) = ctxt |
|
1594 | inst_elem (ctxt, (Int (Notes facts))) = |
|
1595 (* instantiate fact *) |
|
1596 let |
|
1597 val facts = facts |> map_attrib_facts |
|
1598 (Attrib.context_attribute_i ctxt o |
|
1599 Args.map_values I inst_type' inst_term' inst_thm'); |
|
1600 val facts' = |
|
1601 map (apsnd (map (apfst (map inst_thm')))) facts |
|
1602 (* rename fact *) |
|
1603 val facts'' = map (apfst (apfst (NameSpace.qualified prfx))) facts' |
|
1604 (* add attributes *) |
|
1605 val facts''' = map (apfst (apsnd (fn atts => atts @ attribs))) facts'' |
|
1606 in fst (ProofContext.note_thmss_i facts''' ctxt) |
|
1607 end |
|
1608 | inst_elem (ctxt, (Int _)) = ctxt; |
|
1609 |
|
1610 (* FIXME fold o fold *) |
|
1611 fun inst_elems (ctxt, (id, elems)) = Library.foldl inst_elem (ctxt, elems); |
|
1612 |
|
1613 fun inst_elemss ctxt elemss = Library.foldl inst_elems (ctxt, elemss); |
|
1614 |
|
1615 (* main part *) |
|
1616 |
|
1617 val ctxt' = ProofContext.qualified_names ctxt; |
|
1618 in ProofContext.restore_naming ctxt (inst_elemss ctxt' all_elemss) end; |
|
1619 |
|
1620 |
|
1621 (** define locales **) |
1468 (** define locales **) |
1622 |
1469 |
1623 (* print locale *) |
1470 (* print locale *) |
1624 |
1471 |
1625 fun print_locale thy import body = |
1472 fun print_locale thy import body = |
2014 |
1863 |
2015 local |
1864 local |
2016 |
1865 |
2017 (* extract proof obligations (assms and defs) from elements *) |
1866 (* extract proof obligations (assms and defs) from elements *) |
2018 |
1867 |
2019 (* check if defining equation has become t == t, these are dropped |
|
2020 in extract_asms_elem, as they lead to trivial proof obligations *) |
|
2021 (* currently disabled *) |
|
2022 fun check_def (_, (def, _)) = SOME def; |
|
2023 (* |
|
2024 fun check_def (_, (def, _)) = |
|
2025 if def |> Logic.dest_equals |> op aconv |
|
2026 then NONE else SOME def; |
|
2027 *) |
|
2028 |
|
2029 fun extract_asms_elem (ts, Fixes _) = ts |
1868 fun extract_asms_elem (ts, Fixes _) = ts |
|
1869 | extract_asms_elem (ts, Constrains _) = ts |
2030 | extract_asms_elem (ts, Assumes asms) = |
1870 | extract_asms_elem (ts, Assumes asms) = |
2031 ts @ List.concat (map (fn (_, ams) => map (fn (t, _) => t) ams) asms) |
1871 ts @ List.concat (map (fn (_, ams) => map (fn (t, _) => t) ams) asms) |
2032 | extract_asms_elem (ts, Defines defs) = |
1872 | extract_asms_elem (ts, Defines defs) = |
2033 ts @ List.mapPartial check_def defs |
1873 ts @ map (fn (_, (def, _)) => def) defs |
2034 | extract_asms_elem (ts, Notes _) = ts; |
1874 | extract_asms_elem (ts, Notes _) = ts; |
2035 |
1875 |
2036 fun extract_asms_elems (id, elems) = |
1876 fun extract_asms_elems (id, elems) = |
2037 (id, Library.foldl extract_asms_elem ([], elems)); |
1877 (id, Library.foldl extract_asms_elem ([], elems)); |
2038 |
1878 |