37789
|
1 |
(* Author: Alexander Krauss, TU Muenchen
|
|
2 |
Author: Christian Sternagel, University of Innsbruck
|
|
3 |
|
|
4 |
Ad-hoc overloading of constants based on their types.
|
|
5 |
*)
|
|
6 |
|
|
7 |
signature ADHOC_OVERLOADING =
|
|
8 |
sig
|
|
9 |
|
|
10 |
val add_overloaded: string -> theory -> theory
|
|
11 |
val add_variant: string -> string -> theory -> theory
|
|
12 |
|
|
13 |
val show_variants: bool Unsynchronized.ref
|
|
14 |
val setup: theory -> theory
|
|
15 |
|
|
16 |
end
|
|
17 |
|
|
18 |
|
|
19 |
structure Adhoc_Overloading: ADHOC_OVERLOADING =
|
|
20 |
struct
|
|
21 |
|
|
22 |
val show_variants = Unsynchronized.ref false;
|
|
23 |
|
|
24 |
|
|
25 |
(* errors *)
|
|
26 |
|
|
27 |
fun duplicate_variant_err int_name ext_name =
|
|
28 |
error ("Constant " ^ quote int_name ^ " is already a variant of " ^ quote ext_name);
|
|
29 |
|
|
30 |
fun not_overloaded_err name =
|
|
31 |
error ("Constant " ^ quote name ^ " is not declared as overloaded");
|
|
32 |
|
|
33 |
fun already_overloaded_err name =
|
|
34 |
error ("Constant " ^ quote name ^ " is already declared as overloaded");
|
|
35 |
|
|
36 |
fun unresolved_err ctxt (c, T) t reason =
|
|
37 |
error ("Unresolved overloading of " ^ quote c ^ " :: " ^
|
|
38 |
quote (Syntax.string_of_typ ctxt T) ^ " in " ^
|
|
39 |
quote (Syntax.string_of_term ctxt t) ^ " (" ^ reason ^ ")");
|
|
40 |
|
|
41 |
|
|
42 |
(* theory data *)
|
|
43 |
|
|
44 |
structure Overload_Data = Theory_Data
|
|
45 |
(
|
|
46 |
type T =
|
|
47 |
{ internalize : (string * typ) list Symtab.table,
|
|
48 |
externalize : string Symtab.table };
|
|
49 |
val empty = {internalize=Symtab.empty, externalize=Symtab.empty};
|
|
50 |
val extend = I;
|
|
51 |
|
|
52 |
fun merge_ext int_name (ext_name1, ext_name2) =
|
|
53 |
if ext_name1 = ext_name2 then ext_name1
|
|
54 |
else duplicate_variant_err int_name ext_name1;
|
|
55 |
|
|
56 |
fun merge ({internalize=int1, externalize=ext1},
|
|
57 |
{internalize=int2, externalize=ext2}) =
|
|
58 |
{internalize=Symtab.join (K (Library.merge (op =))) (int1, int2),
|
|
59 |
externalize=Symtab.join merge_ext (ext1, ext2)};
|
|
60 |
);
|
|
61 |
|
|
62 |
fun map_tables f g =
|
|
63 |
Overload_Data.map (fn {internalize=int, externalize=ext} =>
|
|
64 |
{internalize=f int, externalize=g ext});
|
|
65 |
|
|
66 |
val is_overloaded = Symtab.defined o #internalize o Overload_Data.get;
|
|
67 |
val get_variants = Symtab.lookup o #internalize o Overload_Data.get;
|
|
68 |
val get_external = Symtab.lookup o #externalize o Overload_Data.get;
|
|
69 |
|
|
70 |
fun add_overloaded ext_name thy =
|
|
71 |
let val _ = not (is_overloaded thy ext_name) orelse already_overloaded_err ext_name;
|
|
72 |
in map_tables (Symtab.update (ext_name, [])) I thy end;
|
|
73 |
|
|
74 |
fun add_variant ext_name name thy =
|
|
75 |
let
|
|
76 |
val _ = is_overloaded thy ext_name orelse not_overloaded_err ext_name;
|
|
77 |
val _ = case get_external thy name of
|
|
78 |
NONE => ()
|
|
79 |
| SOME gen' => duplicate_variant_err name gen';
|
|
80 |
val T = Sign.the_const_type thy name;
|
|
81 |
in
|
|
82 |
map_tables (Symtab.cons_list (ext_name, (name, T)))
|
|
83 |
(Symtab.update (name, ext_name)) thy
|
|
84 |
end
|
|
85 |
|
|
86 |
|
|
87 |
(* check / uncheck *)
|
|
88 |
|
|
89 |
fun unifiable_with ctxt T1 (c, T2) =
|
|
90 |
let
|
|
91 |
val thy = ProofContext.theory_of ctxt;
|
|
92 |
val maxidx1 = Term.maxidx_of_typ T1;
|
|
93 |
val T2' = Logic.incr_tvar (maxidx1 + 1) T2;
|
|
94 |
val maxidx2 = Int.max (maxidx1, Term.maxidx_of_typ T2');
|
|
95 |
in
|
|
96 |
(Sign.typ_unify thy (T1, T2') (Vartab.empty, maxidx2); SOME c)
|
|
97 |
handle Type.TUNIFY => NONE
|
|
98 |
end;
|
|
99 |
|
|
100 |
fun insert_internal_same ctxt t (Const (c, T)) =
|
|
101 |
(case map_filter (unifiable_with ctxt T)
|
|
102 |
(Same.function (get_variants (ProofContext.theory_of ctxt)) c) of
|
|
103 |
[] => unresolved_err ctxt (c, T) t "no instances"
|
|
104 |
| [c'] => Const (c', dummyT)
|
|
105 |
| _ => raise Same.SAME)
|
|
106 |
| insert_internal_same _ _ _ = raise Same.SAME;
|
|
107 |
|
|
108 |
fun insert_external_same ctxt _ (Const (c, T)) =
|
|
109 |
Const (Same.function (get_external (ProofContext.theory_of ctxt)) c, T)
|
|
110 |
| insert_external_same _ _ _ = raise Same.SAME;
|
|
111 |
|
|
112 |
fun gen_check_uncheck replace ts ctxt =
|
|
113 |
Same.capture (Same.map (fn t => Term_Subst.map_aterms_same (replace ctxt t) t)) ts
|
|
114 |
|> Option.map (rpair ctxt);
|
|
115 |
|
|
116 |
val check = gen_check_uncheck insert_internal_same;
|
|
117 |
fun uncheck ts ctxt =
|
|
118 |
if !show_variants then NONE
|
|
119 |
else gen_check_uncheck insert_external_same ts ctxt;
|
|
120 |
|
|
121 |
fun reject_unresolved ts ctxt =
|
|
122 |
let
|
|
123 |
val thy = ProofContext.theory_of ctxt;
|
|
124 |
fun check_unresolved t =
|
|
125 |
case filter (is_overloaded thy o fst) (Term.add_consts t []) of
|
|
126 |
[] => ()
|
|
127 |
| ((c, T) :: _) => unresolved_err ctxt (c, T) t "multiple instances";
|
|
128 |
|
|
129 |
val _ = map check_unresolved ts;
|
|
130 |
in NONE end;
|
|
131 |
|
|
132 |
|
|
133 |
(* setup *)
|
|
134 |
|
|
135 |
val setup = Context.theory_map
|
|
136 |
(Syntax.add_term_check 0 "adhoc_overloading" check
|
|
137 |
#> Syntax.add_term_check 1 "adhoc_overloading_unresolved_check" reject_unresolved
|
|
138 |
#> Syntax.add_term_uncheck 0 "adhoc_overloading" uncheck);
|
|
139 |
|
|
140 |
end
|