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