|
1 signature CLASSY = sig |
|
2 val register_class: binding -> ML_Types.ml_type -> local_theory -> local_theory |
|
3 val register_class_cmd: binding -> string -> local_theory -> local_theory |
|
4 |
|
5 val register_instance_cmd: xstring * Position.T -> binding -> Input.source -> local_theory -> local_theory |
|
6 |
|
7 val check_class: Context.generic -> string * Position.T -> string |
|
8 val print_classes: Context.generic -> unit |
|
9 |
|
10 val resolve: string -> ML_Types.ml_type -> Context.generic -> string |
|
11 |
|
12 val setup: theory -> theory |
|
13 end |
|
14 |
|
15 structure Classy: CLASSY = struct |
|
16 |
|
17 type class_table = (ml_type * (ml_type * string) Name_Space.table) Name_Space.table |
|
18 |
|
19 exception DUP |
|
20 |
|
21 structure Classes = Generic_Data |
|
22 ( |
|
23 type T = class_table |
|
24 val empty = Name_Space.empty_table "ML class" |
|
25 val merge = Name_Space.join_tables (fn _ => raise DUP) (* FIXME consistency check *) |
|
26 val extend = I |
|
27 ) |
|
28 |
|
29 fun list_comb (term: string) (args: string list) = |
|
30 space_implode " " (enclose "(" ")" term :: map (enclose "(" ")") args) |
|
31 |
|
32 fun product [] = [[]] |
|
33 | product (xs :: xss) = |
|
34 maps (fn xs' => map (fn x => x :: xs') xs) (product xss) |
|
35 |
|
36 |
|
37 fun solve entries problem = |
|
38 let |
|
39 fun find (typ, term) = |
|
40 let |
|
41 val (args, candidate) = ML_Types.strip_fun typ |
|
42 in |
|
43 case ML_Types.match candidate problem [] of |
|
44 SOME env => |
|
45 map (ML_Types.subst env) args |
|
46 |> map (solve entries) |
|
47 |> product |
|
48 |> map (list_comb term) |
|
49 | NONE => [] |
|
50 end |
|
51 in |
|
52 maps find entries |
|
53 end |
|
54 |
|
55 fun resolve class typ context = |
|
56 let |
|
57 val classes = Classes.get context |
|
58 val (constructor, table) = Name_Space.get classes class |
|
59 val ML_Types.Con (name, [ML_Types.Var _]) = constructor |
|
60 val entries = map snd (Name_Space.extern_table true (Context.proof_of context) table) |
|
61 val problem = ML_Types.Con (name, [typ]) |
|
62 val solutions = solve entries problem |
|
63 in |
|
64 case solutions of |
|
65 [] => error "no solutions" |
|
66 | [solution] => enclose "(" ")" solution |
|
67 | _ => error "too many solutions" |
|
68 end |
|
69 |
|
70 fun check_class context raw_binding = |
|
71 fst (Name_Space.check context (Classes.get context) raw_binding) |
|
72 |
|
73 val antiquote_setup = |
|
74 ML_Antiquotation.inline (Binding.qualify true "ML" @{binding class}) |
|
75 (Scan.state -- Scan.lift (Parse.position Args.name) >> |
|
76 (fn (context, binding) => quote (check_class context binding))) #> |
|
77 ML_Antiquotation.inline (Binding.qualify true "ML" @{binding resolve}) |
|
78 (Scan.state -- Scan.lift (Parse.ML_source --| @{keyword "::"} -- Parse.position Args.name) >> |
|
79 (fn (context, (source, binding)) => |
|
80 resolve (check_class context binding) (ML_Types.read_ml_type (Input.source_content source)) context)) |
|
81 |
|
82 fun pretty_classes context = |
|
83 let |
|
84 val table = Classes.get context |
|
85 val ctxt = Context.proof_of context |
|
86 val space = Name_Space.space_of_table table |
|
87 val entries = Name_Space.extern_table true ctxt table |
|
88 |
|
89 fun pretty_class ((class, _), (typ, sub_table)) = |
|
90 let |
|
91 val header = Pretty.block [Name_Space.pretty ctxt space class, Pretty.str ":", Pretty.brk 1, ML_Types.pretty typ] |
|
92 |
|
93 val sub_space = Name_Space.space_of_table sub_table |
|
94 val sub_entries = Name_Space.extern_table true ctxt sub_table |
|
95 |
|
96 fun pretty_instance ((instance, _), (typ, _)) = |
|
97 Pretty.item [Name_Space.pretty ctxt sub_space instance, Pretty.str ":", Pretty.brk 1, ML_Types.pretty typ] |
|
98 |
|
99 val instances = map pretty_instance sub_entries |
|
100 in |
|
101 Pretty.item (Pretty.fbreaks (header :: instances)) |
|
102 end |
|
103 in |
|
104 Pretty.big_list "Classes" (map pretty_class entries) |
|
105 end |
|
106 |
|
107 val print_classes = |
|
108 Pretty.writeln o pretty_classes |
|
109 |
|
110 fun register_class binding typ = |
|
111 let |
|
112 val name = |
|
113 (case typ of |
|
114 ML_Types.Con (name, [ML_Types.Var _]) => name |
|
115 | _ => error "Malformed type") |
|
116 fun decl _ context = |
|
117 let |
|
118 val classes = Classes.get context |
|
119 val table = Name_Space.empty_table ("ML instances for " ^ name) |
|
120 val (_, classes') = Name_Space.define context true (binding, (typ, table)) classes |
|
121 in |
|
122 Classes.put classes' context |
|
123 end |
|
124 in |
|
125 Local_Theory.declaration {syntax = false, pervasive = false} decl |
|
126 end |
|
127 |
|
128 fun register_class_cmd binding typ = |
|
129 register_class binding (ML_Types.read_ml_type typ) |
|
130 |
|
131 fun register_instance_cmd raw_binding binding source lthy = |
|
132 let |
|
133 val typ = ML_Types.ml_type_of lthy (Input.source_content source) |
|
134 (* doesn't have any effect except for markup *) |
|
135 val _ = ML_Context.eval_source_in (SOME lthy) ML_Compiler.flags source |
|
136 |
|
137 (* FIXME check correct type *) |
|
138 |
|
139 fun decl _ context = |
|
140 let |
|
141 val classes = Classes.get context |
|
142 val (key, _) = Name_Space.check context classes raw_binding |
|
143 val upd = Name_Space.define context true (binding, (typ, Input.source_content source)) #> snd |
|
144 val classes' = Name_Space.map_table_entry key (apsnd upd) classes |
|
145 in Classes.put classes' context end |
|
146 in |
|
147 Local_Theory.declaration {syntax = false, pervasive = false} decl lthy |
|
148 end |
|
149 |
|
150 val _ = |
|
151 Outer_Syntax.local_theory @{command_keyword "ML.class"} "register new type class" |
|
152 (Parse.binding --| @{keyword "="} -- Parse.cartouche |
|
153 >> (fn (binding, typ) => register_class_cmd binding typ)) |
|
154 |
|
155 val _ = |
|
156 let |
|
157 val opt_binding = |
|
158 Parse.binding --| @{keyword "="} || |
|
159 Parse.position (Scan.succeed ()) >> |
|
160 (fn ((), pos) => Binding.make ("instance" ^ print_int (serial ()), pos)) |
|
161 in |
|
162 Outer_Syntax.local_theory @{command_keyword "ML.instance"} "register new type class instance" |
|
163 (opt_binding -- (Parse.ML_source --| @{keyword "::"} -- Parse.position Args.name) |
|
164 >> (fn (binding, (source, name)) => register_instance_cmd name binding source)) |
|
165 end |
|
166 |
|
167 val _ = |
|
168 Outer_Syntax.command @{command_keyword "ML.print_classes"} "print all registered classes" |
|
169 (Scan.succeed (Toplevel.keep (print_classes o Toplevel.generic_theory_of))) |
|
170 |
|
171 val setup = antiquote_setup |
|
172 |
|
173 end |