author | haftmann |
Wed, 04 Jan 2006 17:04:11 +0100 | |
changeset 18575 | 9ccfd1d1e874 |
parent 18550 | 59b89f625d68 |
child 18593 | 4ce4dba4af07 |
permissions | -rw-r--r-- |
18168 | 1 |
(* Title: Pure/Tools/class_package.ML |
2 |
ID: $Id$ |
|
3 |
Author: Florian Haftmann, TU Muenchen |
|
4 |
||
5 |
Haskell98-like operational view on type classes. |
|
6 |
*) |
|
7 |
||
8 |
signature CLASS_PACKAGE = |
|
9 |
sig |
|
18515 | 10 |
val add_class: bstring -> Locale.expr -> Element.context list -> theory |
11 |
-> ProofContext.context * theory |
|
12 |
val add_class_i: bstring -> Locale.expr -> Element.context_i list -> theory |
|
13 |
-> ProofContext.context * theory |
|
18575 | 14 |
val add_instance_arity: (xstring * string list) * string |
15 |
-> ((bstring * string) * Attrib.src list) list |
|
16 |
-> theory -> Proof.state |
|
17 |
val add_instance_arity_i: (string * sort list) * sort |
|
18 |
-> ((bstring * term) * theory attribute list) list |
|
19 |
-> theory -> Proof.state |
|
18515 | 20 |
val add_classentry: class -> xstring list -> xstring list -> theory -> theory |
18168 | 21 |
val the_consts: theory -> class -> string list |
22 |
val the_tycos: theory -> class -> (string * string) list |
|
18575 | 23 |
val print_classes: theory -> unit |
18168 | 24 |
|
18360 | 25 |
val syntactic_sort_of: theory -> sort -> sort |
18168 | 26 |
val get_arities: theory -> sort -> string -> sort list |
27 |
val get_superclasses: theory -> class -> class list |
|
18304 | 28 |
val get_const_sign: theory -> string -> string -> typ |
18168 | 29 |
val get_inst_consts_sign: theory -> string * class -> (string * typ) list |
30 |
val lookup_const_class: theory -> string -> class option |
|
31 |
val get_classtab: theory -> (string list * (string * string) list) Symtab.table |
|
32 |
||
33 |
type sortcontext = (string * sort) list |
|
34 |
datatype sortlookup = Instance of (class * string) * sortlookup list list |
|
35 |
| Lookup of class list * (string * int) |
|
36 |
val extract_sortctxt: theory -> typ -> sortcontext |
|
37 |
val extract_sortlookup: theory -> typ * typ -> sortlookup list list |
|
38 |
end; |
|
39 |
||
40 |
structure ClassPackage: CLASS_PACKAGE = |
|
41 |
struct |
|
42 |
||
43 |
||
44 |
(* data kind 'Pure/classes' *) |
|
45 |
||
46 |
type class_data = { |
|
18575 | 47 |
superclasses: class list, |
48 |
name_locale: string, |
|
49 |
name_axclass: string, |
|
50 |
var: string, |
|
51 |
consts: (string * typ) list, |
|
52 |
insts: (string * string) list |
|
18168 | 53 |
}; |
54 |
||
18575 | 55 |
structure ClassData = TheoryDataFun ( |
18168 | 56 |
struct |
57 |
val name = "Pure/classes"; |
|
58 |
type T = class_data Symtab.table * class Symtab.table; |
|
59 |
val empty = (Symtab.empty, Symtab.empty); |
|
60 |
val copy = I; |
|
61 |
val extend = I; |
|
62 |
fun merge _ ((t1, r1), (t2, r2))= |
|
63 |
(Symtab.merge (op =) (t1, t2), |
|
64 |
Symtab.merge (op =) (r1, r2)); |
|
18575 | 65 |
fun print thy (tab, _) = |
66 |
let |
|
67 |
fun pretty_class (name, {superclasses, name_locale, name_axclass, var, consts, insts}) = |
|
68 |
(Pretty.block o Pretty.fbreaks) [ |
|
69 |
Pretty.str ("class " ^ name ^ ":"), |
|
70 |
(Pretty.block o Pretty.fbreaks) ( |
|
71 |
Pretty.str "superclasses: " |
|
72 |
:: map Pretty.str superclasses |
|
73 |
), |
|
74 |
Pretty.str ("locale: " ^ name_locale), |
|
75 |
Pretty.str ("axclass: " ^ name_axclass), |
|
76 |
Pretty.str ("class variable: " ^ var), |
|
77 |
(Pretty.block o Pretty.fbreaks) ( |
|
78 |
Pretty.str "constants: " |
|
79 |
:: map (fn (c, ty) => Pretty.str (c ^ " :: " ^ Sign.string_of_typ thy ty)) consts |
|
80 |
), |
|
81 |
(Pretty.block o Pretty.fbreaks) ( |
|
82 |
Pretty.str "instances: " |
|
83 |
:: map (fn (tyco, thyname) => Pretty.str (tyco ^ ", in theory " ^ thyname)) insts |
|
84 |
) |
|
85 |
] |
|
86 |
in |
|
87 |
(Pretty.writeln o Pretty.chunks o map pretty_class o Symtab.dest) tab |
|
88 |
end; |
|
18168 | 89 |
end |
90 |
); |
|
91 |
||
18575 | 92 |
val print_classes = ClassData.print; |
93 |
||
94 |
val lookup_class_data = Symtab.lookup o fst o ClassData.get; |
|
95 |
val lookup_const_class = Symtab.lookup o snd o ClassData.get; |
|
18168 | 96 |
|
97 |
fun get_class_data thy class = |
|
98 |
case lookup_class_data thy class |
|
99 |
of NONE => error ("undeclared class " ^ quote class) |
|
100 |
| SOME data => data; |
|
101 |
||
18575 | 102 |
fun add_class_data (class, (superclasses, name_locale, name_axclass, classvar, consts)) = |
103 |
ClassData.map (fn (classtab, consttab) => ( |
|
104 |
classtab |
|
105 |
|> Symtab.update (class, { |
|
106 |
superclasses = superclasses, |
|
107 |
name_locale = name_locale, |
|
108 |
name_axclass = name_axclass, |
|
109 |
var = classvar, |
|
110 |
consts = consts, |
|
111 |
insts = [] |
|
112 |
}), |
|
113 |
consttab |
|
114 |
|> fold (fn (c, _) => Symtab.update (c, class)) consts |
|
115 |
)); |
|
116 |
||
117 |
fun add_inst_data (class, inst) = |
|
118 |
(ClassData.map o apfst o Symtab.map_entry class) |
|
119 |
(fn {superclasses, name_locale, name_axclass, var, consts, insts} |
|
120 |
=> { |
|
121 |
superclasses = superclasses, |
|
122 |
name_locale = name_locale, |
|
123 |
name_axclass = name_axclass, |
|
124 |
var = var, |
|
125 |
consts = consts, |
|
126 |
insts = insts @ [inst] |
|
127 |
}); |
|
128 |
||
129 |
val the_consts = map fst o #consts oo get_class_data; |
|
130 |
val the_tycos = #insts oo get_class_data; |
|
18168 | 131 |
|
132 |
||
18575 | 133 |
(* classes and instances *) |
18168 | 134 |
|
135 |
local |
|
136 |
||
18515 | 137 |
open Element |
138 |
||
139 |
fun gen_add_class add_locale bname raw_import raw_body thy = |
|
18168 | 140 |
let |
18575 | 141 |
fun subst_clsvar v ty_subst = |
142 |
map_type_tfree (fn u as (w, _) => |
|
143 |
if w = v then ty_subst else TFree u); |
|
144 |
fun extract_assumes c_adds elems = |
|
145 |
let |
|
146 |
fun subst_free ts = |
|
147 |
let |
|
148 |
val get_ty = the o AList.lookup (op =) (fold Term.add_frees ts []); |
|
149 |
val subst_map = map (fn (c, (c', _)) => |
|
150 |
(Free (c, get_ty c), Const (c', get_ty c))) c_adds; |
|
151 |
in map (subst_atomic subst_map) ts end; |
|
152 |
in |
|
153 |
elems |
|
154 |
|> (map o List.mapPartial) |
|
155 |
(fn (Assumes asms) => (SOME o map (map fst o snd)) asms |
|
156 |
| _ => NONE) |
|
157 |
|> Library.flat o Library.flat o Library.flat |
|
158 |
|> subst_free |
|
159 |
end; |
|
18515 | 160 |
fun extract_tyvar_name thy tys = |
161 |
fold (curry add_typ_tfrees) tys [] |
|
18575 | 162 |
|> (fn [(v, sort)] => |
18515 | 163 |
if Sorts.sort_eq (Sign.classes_of thy) (Sign.defaultS thy, sort) |
164 |
then v |
|
18575 | 165 |
else error ("illegal sort constraint on class type variable: " ^ Sign.string_of_sort thy sort) |
18515 | 166 |
| [] => error ("no class type variable") |
167 |
| vs => error ("more than one type variable: " ^ (commas o map (Sign.string_of_typ thy o TFree)) vs)) |
|
168 |
fun extract_tyvar_consts thy elems = |
|
169 |
elems |
|
18550
59b89f625d68
add_local_context now yields imported and body elements seperatly; additional slight clenup in code
haftmann
parents:
18515
diff
changeset
|
170 |
|> Library.flat |
18515 | 171 |
|> List.mapPartial |
172 |
(fn (Fixes consts) => SOME consts |
|
173 |
| _ => NONE) |
|
174 |
|> Library.flat |
|
18575 | 175 |
|> map (fn (c, ty, syn) => |
176 |
((c, the ty), (Syntax.unlocalize_mixfix o Syntax.fix_mixfix c o the) syn)) |
|
177 |
|> `(fn consts => extract_tyvar_name thy (map (snd o fst) consts)) |
|
178 |
|-> (fn v => map ((apfst o apsnd) (subst_clsvar v (TFree (v, [])))) |
|
179 |
#> pair v); |
|
180 |
fun add_global_const v ((c, ty), syn) thy = |
|
18515 | 181 |
thy |
18575 | 182 |
|> Sign.add_consts_i [(c, ty |> subst_clsvar v (TFree (v, Sign.defaultS thy)), syn)] |
183 |
|> `(fn thy => (c, (Sign.intern_const thy c, ty))) |
|
184 |
fun add_global_constraint v class (_, (c, ty)) thy = |
|
18515 | 185 |
thy |
18575 | 186 |
|> Sign.add_const_constraint_i (c, subst_clsvar v (TVar ((v, 0), [class])) ty); |
18515 | 187 |
fun print_ctxt ctxt elem = |
188 |
map Pretty.writeln (Element.pretty_ctxt ctxt elem) |
|
18168 | 189 |
in |
190 |
thy |
|
18515 | 191 |
|> add_locale bname raw_import raw_body |
18575 | 192 |
|-> (fn ((import_elems, body_elems), ctxt) => |
193 |
`(fn thy => Locale.intern thy bname) |
|
18515 | 194 |
#-> (fn name_locale => |
18575 | 195 |
`(fn thy => extract_tyvar_consts thy body_elems) |
196 |
#-> (fn (v, c_defs) => |
|
197 |
fold_map (add_global_const v) c_defs |
|
198 |
#-> (fn c_adds => |
|
199 |
AxClass.add_axclass_i (bname, Sign.defaultS thy) |
|
200 |
(map (Thm.no_attributes o pair "") (extract_assumes c_adds (import_elems @ body_elems))) |
|
201 |
#-> (fn _ => |
|
202 |
`(fn thy => Sign.intern_class thy bname) |
|
18515 | 203 |
#-> (fn name_axclass => |
18575 | 204 |
fold (add_global_constraint v name_axclass) c_adds |
205 |
#> add_class_data (name_locale, ([], name_locale, name_axclass, v, map snd c_adds)) |
|
206 |
#> tap (fn _ => (map o map) (print_ctxt ctxt) import_elems) |
|
207 |
#> tap (fn _ => (map o map) (print_ctxt ctxt) body_elems) |
|
18515 | 208 |
#> pair ctxt |
18575 | 209 |
)))))) |
18168 | 210 |
end; |
211 |
||
212 |
in |
|
213 |
||
18515 | 214 |
val add_class = gen_add_class (Locale.add_locale_context true); |
215 |
val add_class_i = gen_add_class (Locale.add_locale_context_i true); |
|
18168 | 216 |
|
217 |
end; (* local *) |
|
218 |
||
18575 | 219 |
fun gen_instance_arity prep_arity add_defs tap_def raw_arity raw_defs thy = |
220 |
let |
|
221 |
val dest_def = Theory.dest_def (Sign.pp thy) handle TERM (msg, _) => error msg; |
|
222 |
val arity as (tyco, asorts, sort) = prep_arity thy ((fn ((x, y), z) => (x, y, z)) raw_arity); |
|
223 |
val ty_inst = Type (tyco, map2 (curry TVar o rpair 0) (Term.invent_names [] "'a" (length asorts)) asorts) |
|
224 |
fun get_c_req class = |
|
225 |
let |
|
226 |
val data = get_class_data thy class; |
|
227 |
val subst_ty = map_type_tfree (fn (var as (v, _)) => |
|
228 |
if #var data = v then ty_inst else TFree var) |
|
229 |
in (map (apsnd subst_ty) o #consts) data end; |
|
230 |
val c_req = (Library.flat o map get_c_req) sort; |
|
231 |
fun get_remove_contraint c thy = |
|
232 |
let |
|
233 |
val ty1 = Sign.the_const_constraint thy c; |
|
234 |
val ty2 = Sign.the_const_type thy c; |
|
235 |
in |
|
236 |
thy |
|
237 |
|> Sign.add_const_constraint_i (c, ty2) |
|
238 |
|> pair (c, ty1) |
|
239 |
end; |
|
240 |
fun get_c_given thy = map (fst o dest_def o snd o tap_def thy o fst) raw_defs; |
|
241 |
fun check_defs c_given c_req thy = |
|
242 |
let |
|
243 |
fun eq_c ((c1, ty1), (c2, ty2)) = c1 = c2 andalso Sign.typ_instance thy (ty1, ty2) |
|
244 |
val _ = case fold (remove eq_c) c_given c_req |
|
245 |
of [] => () |
|
246 |
| cs => error ("no definition(s) given for" |
|
247 |
^ (commas o map (fn (c, ty) => quote (c ^ "::" ^ Sign.string_of_typ thy ty))) cs); |
|
248 |
val _ = case fold (remove eq_c) c_req c_given |
|
249 |
of [] => () |
|
250 |
| cs => error ("superfluous definition(s) given for" |
|
251 |
^ (commas o map (fn (c, ty) => quote (c ^ "::" ^ Sign.string_of_typ thy ty))) cs); |
|
252 |
in thy end; |
|
253 |
in |
|
254 |
thy |
|
255 |
|> fold_map get_remove_contraint (map fst c_req) |
|
256 |
||> tap (fn thy => check_defs (get_c_given thy) c_req) |
|
257 |
||> add_defs (true, raw_defs) |
|
258 |
|-> (fn cs => fold Sign.add_const_constraint_i cs) |
|
259 |
|> AxClass.instance_arity_i arity |
|
260 |
end; |
|
261 |
||
262 |
val add_instance_arity = fn x => gen_instance_arity (AxClass.read_arity) IsarThy.add_defs read_axm x; |
|
263 |
val add_instance_arity_i = fn x => gen_instance_arity (AxClass.cert_arity) IsarThy.add_defs_i (K I) x; |
|
264 |
||
18168 | 265 |
|
266 |
(* class queries *) |
|
267 |
||
18360 | 268 |
fun is_class thy cls = lookup_class_data thy cls |> Option.map (not o null o #consts) |> the_default false; |
18168 | 269 |
|
18360 | 270 |
fun syntactic_sort_of thy sort = |
271 |
let |
|
272 |
val classes = Sign.classes_of thy; |
|
273 |
fun get_sort cls = |
|
274 |
if is_class thy cls |
|
275 |
then [cls] |
|
276 |
else syntactic_sort_of thy (Sorts.superclasses classes cls); |
|
277 |
in |
|
278 |
map get_sort sort |
|
279 |
|> Library.flat |
|
280 |
|> Sorts.norm_sort classes |
|
281 |
end; |
|
18168 | 282 |
|
283 |
fun get_arities thy sort tycon = |
|
18515 | 284 |
Sorts.mg_domain (Sign.classes_arities_of thy) tycon (syntactic_sort_of thy sort) |
18360 | 285 |
|> map (syntactic_sort_of thy); |
18168 | 286 |
|
287 |
fun get_superclasses thy class = |
|
18515 | 288 |
if is_class thy class |
289 |
then |
|
290 |
Sorts.superclasses (Sign.classes_of thy) class |
|
291 |
|> syntactic_sort_of thy |
|
292 |
else |
|
293 |
error ("no syntactic class: " ^ class); |
|
18168 | 294 |
|
295 |
||
296 |
(* instance queries *) |
|
297 |
||
18575 | 298 |
fun mk_const_sign thy class tvar ty = |
18168 | 299 |
let |
18575 | 300 |
val (ty', thaw) = Type.freeze_thaw_type ty; |
301 |
val tvars_used = Term.add_tfreesT ty' []; |
|
18304 | 302 |
val tvar_rename = hd (Term.invent_names (map fst tvars_used) tvar 1); |
303 |
in |
|
18575 | 304 |
ty' |
18304 | 305 |
|> map_type_tfree (fn (tvar', sort) => |
306 |
if Sorts.sort_eq (Sign.classes_of thy) ([class], sort) |
|
307 |
then TFree (tvar, []) |
|
308 |
else if tvar' = tvar |
|
18335 | 309 |
then TVar ((tvar_rename, 0), sort) |
18304 | 310 |
else TFree (tvar', sort)) |
18335 | 311 |
|> thaw |
18304 | 312 |
end; |
18168 | 313 |
|
18575 | 314 |
fun get_const_sign thy tvar const = |
315 |
let |
|
316 |
val class = (the o lookup_const_class thy) const; |
|
317 |
val ty = Sign.the_const_constraint thy const; |
|
318 |
in mk_const_sign thy class tvar ty end; |
|
319 |
||
18168 | 320 |
fun get_inst_consts_sign thy (tyco, class) = |
321 |
let |
|
322 |
val consts = the_consts thy class; |
|
323 |
val arities = get_arities thy [class] tyco; |
|
18304 | 324 |
val const_signs = map (get_const_sign thy "'a") consts; |
325 |
val vars_used = fold (fn ty => curry (gen_union (op =)) |
|
326 |
(map fst (typ_tfrees ty) |> remove (op =) "'a")) const_signs []; |
|
18168 | 327 |
val vars_new = Term.invent_names vars_used "'a" (length arities); |
18330 | 328 |
val typ_arity = Type (tyco, map2 (curry TFree) vars_new arities); |
18168 | 329 |
val instmem_signs = |
18335 | 330 |
map (typ_subst_TVars [(("'a", 0), typ_arity)]) const_signs; |
18168 | 331 |
in consts ~~ instmem_signs end; |
332 |
||
333 |
fun get_classtab thy = |
|
334 |
Symtab.fold |
|
18575 | 335 |
(fn (class, { consts = consts, insts = insts, ... }) => |
336 |
Symtab.update_new (class, (map fst consts, insts))) |
|
337 |
(fst (ClassData.get thy)) Symtab.empty; |
|
18168 | 338 |
|
339 |
||
340 |
(* extracting dictionary obligations from types *) |
|
341 |
||
342 |
type sortcontext = (string * sort) list; |
|
343 |
||
18335 | 344 |
fun extract_sortctxt thy ty = |
345 |
(typ_tfrees o Type.no_tvars) ty |
|
18360 | 346 |
|> map (apsnd (syntactic_sort_of thy)) |
18168 | 347 |
|> filter (not o null o snd); |
348 |
||
349 |
datatype sortlookup = Instance of (class * string) * sortlookup list list |
|
350 |
| Lookup of class list * (string * int) |
|
351 |
||
352 |
fun extract_sortlookup thy (raw_typ_def, raw_typ_use) = |
|
353 |
let |
|
354 |
val typ_def = Type.varifyT raw_typ_def; |
|
355 |
val typ_use = Type.varifyT raw_typ_use; |
|
356 |
val match_tab = Sign.typ_match thy (typ_def, typ_use) Vartab.empty; |
|
357 |
fun tab_lookup vname = (the o Vartab.lookup match_tab) (vname, 0); |
|
358 |
fun get_superclass_derivation (subclasses, superclass) = |
|
359 |
(the oo get_first) (fn subclass => |
|
360 |
Sorts.class_le_path (Sign.classes_of thy) (subclass, superclass) |
|
361 |
) subclasses; |
|
362 |
fun mk_class_deriv thy subclasses superclass = |
|
363 |
case get_superclass_derivation (subclasses, superclass) |
|
18515 | 364 |
of (subclass::deriv) => |
365 |
((rev o filter (is_class thy)) deriv, find_index_eq subclass subclasses); |
|
18168 | 366 |
fun mk_lookup (sort_def, (Type (tycon, tys))) = |
367 |
let |
|
18330 | 368 |
val arity_lookup = map2 (curry mk_lookup) |
18360 | 369 |
(map (syntactic_sort_of thy) (Sorts.mg_domain (Sign.classes_arities_of thy) tycon sort_def)) tys |
18168 | 370 |
in map (fn class => Instance ((class, tycon), arity_lookup)) sort_def end |
371 |
| mk_lookup (sort_def, TVar ((vname, _), sort_use)) = |
|
372 |
let |
|
373 |
fun mk_look class = |
|
18515 | 374 |
let val (deriv, classindex) = mk_class_deriv thy (syntactic_sort_of thy sort_use) class |
18168 | 375 |
in Lookup (deriv, (vname, classindex)) end; |
376 |
in map mk_look sort_def end; |
|
377 |
in |
|
18335 | 378 |
extract_sortctxt thy ((fst o Type.freeze_thaw_type) raw_typ_def) |
18168 | 379 |
|> map (tab_lookup o fst) |
18360 | 380 |
|> map (apfst (syntactic_sort_of thy)) |
18168 | 381 |
|> filter (not o null o fst) |
382 |
|> map mk_lookup |
|
383 |
end; |
|
384 |
||
385 |
||
18335 | 386 |
(* intermediate auxiliary *) |
18168 | 387 |
|
18575 | 388 |
fun add_classentry raw_class raw_cs raw_insts thy = |
18168 | 389 |
let |
390 |
val class = Sign.intern_class thy raw_class; |
|
18575 | 391 |
val cs = raw_cs |> map (Sign.intern_const thy); |
392 |
val insts = map (rpair (Context.theory_name thy) o Sign.intern_type thy) raw_insts; |
|
18168 | 393 |
in |
394 |
thy |
|
18575 | 395 |
|> add_class_data (class, ([], "", class, "", map (rpair dummyT) cs)) |
396 |
|> fold (curry add_inst_data class) insts |
|
18335 | 397 |
end; |
18515 | 398 |
|
399 |
||
400 |
(* toplevel interface *) |
|
401 |
||
402 |
local |
|
403 |
||
404 |
structure P = OuterParse |
|
405 |
and K = OuterKeyword |
|
406 |
||
407 |
in |
|
408 |
||
18575 | 409 |
val (classK, instanceK) = ("class", "class_instance") |
18515 | 410 |
|
411 |
val locale_val = |
|
412 |
(P.locale_expr -- |
|
413 |
Scan.optional (P.$$$ "+" |-- P.!!! (Scan.repeat1 P.context_element)) [] || |
|
414 |
Scan.repeat1 P.context_element >> pair Locale.empty); |
|
415 |
||
416 |
val classP = |
|
417 |
OuterSyntax.command classK "operational type classes" K.thy_decl |
|
418 |
(P.name -- Scan.optional (P.$$$ "=" |-- P.!!! locale_val) (Locale.empty, []) |
|
419 |
>> (Toplevel.theory_context |
|
18575 | 420 |
o (fn f => swap o f) o (fn (bname, (expr, elems)) => add_class bname expr elems))); |
18515 | 421 |
|
18575 | 422 |
val instanceP = |
423 |
OuterSyntax.command instanceK "" K.thy_goal |
|
424 |
(P.xname -- (P.$$$ "::" |-- P.!!! P.arity) |
|
425 |
-- Scan.repeat1 P.spec_name |
|
426 |
>> (Toplevel.theory_theory_to_proof |
|
427 |
o (fn ((tyco, (asorts, sort)), defs) => add_instance_arity ((tyco, asorts), sort) defs))); |
|
428 |
||
429 |
val _ = OuterSyntax.add_parsers [classP, instanceP]; |
|
18515 | 430 |
|
431 |
end; (* local *) |
|
432 |
||
18168 | 433 |
|
434 |
(* setup *) |
|
435 |
||
18575 | 436 |
val _ = Context.add_setup [ClassData.init]; |
18168 | 437 |
|
438 |
end; (* struct *) |