libisabelle-protocol/classy/classy.ML
changeset 59469 5c56f14bea53
parent 59340 097347b8910e
equal deleted inserted replaced
59468:288e0d80578d 59469:5c56f14bea53
       
     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