1 (* Title: Pure/General/defs.ML |
1 (* Title: Pure/General/defs.ML |
2 ID: $Id$ |
2 ID: $Id$ |
3 Author: Steven Obua, TU Muenchen |
3 Author: Steven Obua, TU Muenchen |
4 |
4 |
5 Checks if definitions preserve consistency of logic by enforcing |
5 Checks if definitions preserve consistency of logic by enforcing that |
6 that there are no cyclic definitions. The algorithm is described in |
6 there are no cyclic definitions. The algorithm is described in "An |
7 "An Algorithm for Determining Definitional Cycles in Higher-Order Logic with Overloading", |
7 Algorithm for Determining Definitional Cycles in Higher-Order Logic |
8 Steven Obua, technical report, to be written :-) |
8 with Overloading", Steven Obua, technical report, to be written :-) |
9 *) |
9 *) |
10 |
10 |
11 signature DEFS = |
11 signature DEFS = |
12 sig |
12 sig |
|
13 (*true: record the full chain of definitions that lead to a circularity*) |
|
14 val chain_history: bool ref |
13 type graph |
15 type graph |
14 val empty: graph |
16 val empty: graph |
15 val declare: string * typ -> graph -> graph |
17 val declare: theory -> string * typ -> graph -> graph |
16 val define: Pretty.pp -> string * typ -> string -> (string * typ) list -> graph -> graph |
18 val define: theory -> string * typ -> string -> (string * typ) list -> graph -> graph |
17 val finalize: string * typ -> graph -> graph |
19 val finalize: theory -> string * typ -> graph -> graph |
18 val merge: Pretty.pp -> graph -> graph -> graph |
20 val merge: Pretty.pp -> graph -> graph -> graph |
19 |
21 val finals: graph -> typ list Symtab.table |
20 val finals : graph -> (typ list) Symtab.table |
|
21 |
|
22 (* If set to true then the exceptions CIRCULAR and INFINITE_CHAIN return the full |
|
23 chain of definitions that lead to the exception. In the beginning, chain_history |
|
24 is initialized with the Isabelle environment variable DEFS_CHAIN_HISTORY. *) |
|
25 val set_chain_history : bool -> unit |
|
26 val chain_history : unit -> bool |
|
27 |
|
28 datatype overloadingstate = Open | Closed | Final |
22 datatype overloadingstate = Open | Closed | Final |
29 |
23 val overloading_info: graph -> string -> (typ * (string*typ) list * overloadingstate) option |
30 val overloading_info : graph -> string -> (typ * (string*typ) list * overloadingstate) option |
24 val monomorphic: graph -> string -> bool |
31 val fast_overloading_info : graph -> string -> (typ * int * overloadingstate) option |
|
32 end |
25 end |
33 |
26 |
34 structure Defs :> DEFS = struct |
27 structure Defs :> DEFS = struct |
35 |
28 |
36 type tyenv = Type.tyenv |
29 type tyenv = Type.tyenv |
59 fun get_defnode' graph noderef defname = |
52 fun get_defnode' graph noderef defname = |
60 Symtab.lookup (get_nodedefs (the (Symtab.lookup (graph, noderef))), defname) |
53 Symtab.lookup (get_nodedefs (the (Symtab.lookup (graph, noderef))), defname) |
61 |
54 |
62 fun table_size table = Symtab.foldl (fn (x, _) => x+1) (0, table) |
55 fun table_size table = Symtab.foldl (fn (x, _) => x+1) (0, table) |
63 |
56 |
64 datatype graphaction = Declare of string * typ |
57 datatype graphaction = |
65 | Define of string * typ * string * string * (string * typ) list |
58 Declare of string * typ |
66 | Finalize of string * typ |
59 | Define of string * typ * string * string * (string * typ) list |
67 |
60 | Finalize of string * typ |
68 type graph = int * (string Symtab.table) * (graphaction list) * (node Symtab.table) |
61 |
69 |
62 type graph = int * string Symtab.table * graphaction list * node Symtab.table |
70 val CHAIN_HISTORY = |
63 |
71 let |
64 val chain_history = ref true |
72 fun f c = if Char.isSpace c then "" else String.str (Char.toUpper c) |
|
73 val env = String.translate f (getenv "DEFS_CHAIN_HISTORY") |
|
74 in |
|
75 ref (env = "ON" orelse env = "TRUE") |
|
76 end |
|
77 |
|
78 fun set_chain_history b = CHAIN_HISTORY := b |
|
79 fun chain_history () = !CHAIN_HISTORY |
|
80 |
65 |
81 val empty = (0, Symtab.empty, [], Symtab.empty) |
66 val empty = (0, Symtab.empty, [], Symtab.empty) |
82 |
67 |
83 exception DEFS of string; |
68 exception DEFS of string; |
84 exception CIRCULAR of (typ * string * string) list; |
69 exception CIRCULAR of (typ * string * string) list; |
97 fun checkT' (Type (a, Ts)) = Type (a, map checkT' Ts) |
82 fun checkT' (Type (a, Ts)) = Type (a, map checkT' Ts) |
98 | checkT' (TFree (a, _)) = TVar ((a, 0), []) (* FIXME !? *) |
83 | checkT' (TFree (a, _)) = TVar ((a, 0), []) (* FIXME !? *) |
99 | checkT' (TVar ((a, 0), _)) = TVar ((a, 0), []) |
84 | checkT' (TVar ((a, 0), _)) = TVar ((a, 0), []) |
100 | checkT' (T as TVar _) = raise TYPE ("Illegal schematic type variable encountered", [T], []); |
85 | checkT' (T as TVar _) = raise TYPE ("Illegal schematic type variable encountered", [T], []); |
101 |
86 |
102 val checkT = Term.compress_type o checkT'; |
87 fun checkT thy = Compress.typ thy o checkT'; |
103 |
88 |
104 fun rename ty1 ty2 = Logic.incr_tvar ((maxidx_of_typ ty1)+1) ty2; |
89 fun rename ty1 ty2 = Logic.incr_tvar ((maxidx_of_typ ty1)+1) ty2; |
105 |
90 |
106 fun subst_incr_tvar inc t = |
91 fun subst_incr_tvar inc t = |
107 if (inc > 0) then |
92 if (inc > 0) then |
151 case unify ty1 ty2 of |
136 case unify ty1 ty2 of |
152 NONE => NONE |
137 NONE => NONE |
153 | SOME s => SOME (max, merge s1 s, merge s2 s) |
138 | SOME s => SOME (max, merge s1 s, merge s2 s) |
154 end |
139 end |
155 |
140 |
156 fun can_be_unified_r ty1 ty2 = |
141 fun can_be_unified_r ty1 ty2 = is_some (unify ty1 (rename ty1 ty2)) |
157 let |
142 fun can_be_unified ty1 ty2 = is_some (unify ty1 ty2) |
158 val ty2 = rename ty1 ty2 |
|
159 in |
|
160 case unify ty1 ty2 of |
|
161 NONE => false |
|
162 | _ => true |
|
163 end |
|
164 |
|
165 fun can_be_unified ty1 ty2 = |
|
166 case unify ty1 ty2 of |
|
167 NONE => false |
|
168 | _ => true |
|
169 |
143 |
170 fun normalize_edge_idx (edge as (maxidx, u1, v1, history)) = |
144 fun normalize_edge_idx (edge as (maxidx, u1, v1, history)) = |
171 if maxidx <= 1000000 then edge else |
145 if maxidx <= 1000000 then edge else |
172 let |
146 let |
173 |
147 |
242 g |
216 g |
243 else |
217 else |
244 def_err "constant is already declared with different type" |
218 def_err "constant is already declared with different type" |
245 end |
219 end |
246 |
220 |
247 fun declare'' g (name, ty) = declare' g (name, checkT ty) |
221 fun declare'' thy g (name, ty) = declare' g (name, checkT thy ty) |
248 |
222 |
249 val axcounter = ref (IntInf.fromInt 0) |
223 val axcounter = ref (IntInf.fromInt 0) |
250 fun newaxname axmap axname = |
224 fun newaxname axmap axname = |
251 let |
225 let |
252 val c = !axcounter |
226 val c = !axcounter |
328 fun connect (maxidx2, alpha2, beta2, history) = |
302 fun connect (maxidx2, alpha2, beta2, history) = |
329 case unify_r (Int.max (maxidx1, maxidx2)) beta1 alpha2 of |
303 case unify_r (Int.max (maxidx1, maxidx2)) beta1 alpha2 of |
330 NONE => NONE |
304 NONE => NONE |
331 | SOME (max, sleft, sright) => |
305 | SOME (max, sleft, sright) => |
332 SOME (max, subst sleft alpha1, subst sright beta2, |
306 SOME (max, subst sleft alpha1, subst sright beta2, |
333 if !CHAIN_HISTORY then |
307 if !chain_history then |
334 ((subst sleft beta1, bodyn, defname):: |
308 ((subst sleft beta1, bodyn, defname):: |
335 (subst_history sright history)) |
309 (subst_history sright history)) |
336 else []) |
310 else []) |
337 val links' = List.mapPartial connect links |
311 val links' = List.mapPartial connect links |
338 in |
312 in |
490 val actions' = (Define (mainref, ty, axname, orig_axname, body))::actions |
464 val actions' = (Define (mainref, ty, axname, orig_axname, body))::actions |
491 in |
465 in |
492 (cost+3, axmap, actions', graph) |
466 (cost+3, axmap, actions', graph) |
493 end handle ex => translate_ex axmap ex |
467 end handle ex => translate_ex axmap ex |
494 |
468 |
495 fun define'' (g as (cost, axmap, actions, graph)) (mainref, ty) orig_axname body = |
469 fun define'' thy (g as (cost, axmap, actions, graph)) (mainref, ty) orig_axname body = |
496 let |
470 let |
497 val ty = checkT ty |
471 val ty = checkT thy ty |
498 fun checkbody (n, t) = |
472 fun checkbody (n, t) = |
499 let |
473 let |
500 val (Node (_, _, _,_, closed)) = getnode graph n |
474 val (Node (_, _, _,_, closed)) = getnode graph n |
501 in |
475 in |
502 case closed of |
476 case closed of |
503 Final => NONE |
477 Final => NONE |
504 | _ => SOME (n, checkT t) |
478 | _ => SOME (n, checkT thy t) |
505 end |
479 end |
506 val body = distinct (List.mapPartial checkbody body) |
480 val body = distinct (List.mapPartial checkbody body) |
507 val (axmap, axname) = newaxname axmap orig_axname |
481 val (axmap, axname) = newaxname axmap orig_axname |
508 in |
482 in |
509 define' (cost, axmap, actions, graph) (mainref, ty) axname orig_axname body |
483 define' (cost, axmap, actions, graph) (mainref, ty) axname orig_axname body |
601 in |
575 in |
602 (cost+1, axmap, history', graph') |
576 (cost+1, axmap, history', graph') |
603 end |
577 end |
604 end |
578 end |
605 |
579 |
606 fun finalize'' g (noderef, ty) = finalize' g (noderef, checkT ty) |
580 fun finalize'' thy g (noderef, ty) = finalize' g (noderef, checkT thy ty) |
607 |
581 |
608 fun update_axname ax orig_ax (cost, axmap, history, graph) = |
582 fun update_axname ax orig_ax (cost, axmap, history, graph) = |
609 (cost, Symtab.update ((ax, orig_ax), axmap), history, graph) |
583 (cost, Symtab.update ((ax, orig_ax), axmap), history, graph) |
610 |
584 |
611 fun merge' (Declare cty, g) = declare' g cty |
585 fun merge' (Declare cty, g) = declare' g cty |
638 NONE => NONE |
612 NONE => NONE |
639 | SOME (Node (ty, defnodes, _, _, state)) => |
613 | SOME (Node (ty, defnodes, _, _, state)) => |
640 SOME (ty, map translate (Symtab.dest defnodes), state) |
614 SOME (ty, map translate (Symtab.dest defnodes), state) |
641 end |
615 end |
642 |
616 |
643 fun fast_overloading_info (_, _, _, graph) c = |
617 |
644 let |
618 (* monomorphic consts -- neither parametric nor ad-hoc polymorphism *) |
645 fun count (c, _) = c+1 |
619 |
646 in |
620 fun monomorphicT (Type (_, Ts)) = forall monomorphicT Ts |
647 case Symtab.lookup (graph, c) of |
621 | monomorphicT _ = false |
648 NONE => NONE |
622 |
649 | SOME (Node (ty, defnodes, _, _, state)) => |
623 fun monomorphic (_, _, _, graph) c = |
650 SOME (ty, Symtab.foldl count (0, defnodes), state) |
624 (case Symtab.lookup (graph, c) of |
651 end |
625 NONE => true |
|
626 | SOME (Node (ty, defnodes, _, _, _)) => |
|
627 Symtab.min_key defnodes = Symtab.max_key defnodes andalso |
|
628 monomorphicT ty); |
652 |
629 |
653 |
630 |
654 |
631 |
655 (** diagnostics **) |
632 (** diagnostics **) |
656 |
633 |
661 fun pretty_path pp path = fold_rev (fn (T, c, def) => |
638 fun pretty_path pp path = fold_rev (fn (T, c, def) => |
662 fn [] => [Pretty.block (pretty_const pp (c, T))] |
639 fn [] => [Pretty.block (pretty_const pp (c, T))] |
663 | prts => Pretty.block (pretty_const pp (c, T) @ |
640 | prts => Pretty.block (pretty_const pp (c, T) @ |
664 [Pretty.brk 1, Pretty.str ("depends via " ^ quote def ^ " on")]) :: prts) path []; |
641 [Pretty.brk 1, Pretty.str ("depends via " ^ quote def ^ " on")]) :: prts) path []; |
665 |
642 |
666 fun chain_history_msg s = (* FIXME huh!? *) |
|
667 if chain_history () then s ^ ": " |
|
668 else s ^ " (set DEFS_CHAIN_HISTORY=ON for full history): "; |
|
669 |
|
670 fun defs_circular pp path = |
643 fun defs_circular pp path = |
671 Pretty.str (chain_history_msg "Cyclic dependency of definitions") :: pretty_path pp path |
644 Pretty.str "Cyclic dependency of definitions: " :: pretty_path pp path |
672 |> Pretty.chunks |> Pretty.string_of; |
645 |> Pretty.chunks |> Pretty.string_of; |
673 |
646 |
674 fun defs_infinite_chain pp path = |
647 fun defs_infinite_chain pp path = |
675 Pretty.str (chain_history_msg "Infinite chain of definitions") :: pretty_path pp path |
648 Pretty.str "Infinite chain of definitions: " :: pretty_path pp path |
676 |> Pretty.chunks |> Pretty.string_of; |
649 |> Pretty.chunks |> Pretty.string_of; |
677 |
650 |
678 fun defs_clash def1 def2 = "Type clash in definitions " ^ quote def1 ^ " and " ^ quote def2; |
651 fun defs_clash def1 def2 = "Type clash in definitions " ^ quote def1 ^ " and " ^ quote def2; |
679 |
652 |
680 fun defs_final pp const = |
653 fun defs_final pp const = |
682 |> Pretty.block |> Pretty.string_of; |
655 |> Pretty.block |> Pretty.string_of; |
683 |
656 |
684 |
657 |
685 (* external interfaces *) |
658 (* external interfaces *) |
686 |
659 |
687 fun declare const defs = |
660 fun declare thy const defs = |
688 if_none (try (declare'' defs) const) defs; |
661 if_none (try (declare'' thy defs) const) defs; |
689 |
662 |
690 fun define pp const name rhs defs = |
663 fun define thy const name rhs defs = |
691 define'' defs const name rhs |
664 define'' thy defs const name rhs |
692 handle DEFS msg => sys_error msg |
665 handle DEFS msg => sys_error msg |
693 | CIRCULAR path => error (defs_circular pp path) |
666 | CIRCULAR path => error (defs_circular (Sign.pp thy) path) |
694 | INFINITE_CHAIN path => error (defs_infinite_chain pp path) |
667 | INFINITE_CHAIN path => error (defs_infinite_chain (Sign.pp thy) path) |
695 | CLASH (_, def1, def2) => error (defs_clash def1 def2) |
668 | CLASH (_, def1, def2) => error (defs_clash def1 def2) |
696 | FINAL const => error (defs_final pp const); |
669 | FINAL const => error (defs_final (Sign.pp thy) const); |
697 |
670 |
698 fun finalize const defs = |
671 fun finalize thy const defs = |
699 finalize'' defs const handle DEFS msg => sys_error msg; |
672 finalize'' thy defs const handle DEFS msg => sys_error msg; |
700 |
673 |
701 fun merge pp defs1 defs2 = |
674 fun merge pp defs1 defs2 = |
702 merge'' defs1 defs2 |
675 merge'' defs1 defs2 |
703 handle CIRCULAR namess => error (defs_circular pp namess) |
676 handle CIRCULAR namess => error (defs_circular pp namess) |
704 | INFINITE_CHAIN namess => error (defs_infinite_chain pp namess); |
677 | INFINITE_CHAIN namess => error (defs_infinite_chain pp namess); |