src/HOL/Tools/Function/function_common.ML
author haftmann
Sun, 10 Nov 2013 15:05:06 +0100
changeset 55747 45a5523d4a63
parent 54740 59ef06cda7b9
child 56082 91f54d386680
permissions -rw-r--r--
qualifed popular user space names
     1 (*  Title:      HOL/Tools/Function/function_common.ML
     2     Author:     Alexander Krauss, TU Muenchen
     3 
     4 Common definitions and other infrastructure for the function package.
     5 *)
     6 
     7 signature FUNCTION_DATA =
     8 sig
     9 
    10 type info =
    11  {is_partial : bool,
    12   defname : string,
    13     (* contains no logical entities: invariant under morphisms: *)
    14   add_simps : (binding -> binding) -> string -> (binding -> binding) ->
    15     Attrib.src list -> thm list -> local_theory -> thm list * local_theory,
    16   fnames : string list,
    17   case_names : string list,
    18   fs : term list,
    19   R : term,
    20   dom: term,
    21   psimps: thm list,
    22   pinducts: thm list,
    23   simps : thm list option,
    24   inducts : thm list option,
    25   termination : thm,
    26   cases : thm list,
    27   pelims: thm list list,
    28   elims: thm list list option}
    29 
    30 end
    31 
    32 structure Function_Data : FUNCTION_DATA =
    33 struct
    34 
    35 type info =
    36  {is_partial : bool,
    37   defname : string,
    38     (* contains no logical entities: invariant under morphisms: *)
    39   add_simps : (binding -> binding) -> string -> (binding -> binding) ->
    40     Attrib.src list -> thm list -> local_theory -> thm list * local_theory,
    41   fnames : string list,
    42   case_names : string list,
    43   fs : term list,
    44   R : term,
    45   dom: term,
    46   psimps: thm list,
    47   pinducts: thm list,
    48   simps : thm list option,
    49   inducts : thm list option,
    50   termination : thm,
    51   cases : thm list,
    52   pelims : thm list list,
    53   elims : thm list list option}
    54 
    55 end
    56 
    57 signature FUNCTION_COMMON =
    58 sig
    59   include FUNCTION_DATA
    60   val profile : bool Unsynchronized.ref
    61   val PROFILE : string -> ('a -> 'b) -> 'a -> 'b
    62   val mk_acc : typ -> term -> term
    63   val function_name : string -> string
    64   val graph_name : string -> string
    65   val rel_name : string -> string
    66   val dom_name : string -> string
    67   val apply_termination_rule : Proof.context -> int -> tactic
    68   datatype function_result = FunctionResult of
    69    {fs: term list,
    70     G: term,
    71     R: term,
    72     dom: term,
    73     psimps : thm list,
    74     simple_pinducts : thm list,
    75     cases : thm list,
    76     pelims : thm list list,
    77     termination : thm,
    78     domintros : thm list option}
    79   val transform_function_data : info -> morphism -> info
    80   val get_function : Proof.context -> (term * info) Item_Net.T
    81   val import_function_data : term -> Proof.context -> info option
    82   val import_last_function : Proof.context -> info option
    83   val add_function_data : info -> Context.generic -> Context.generic
    84   structure Termination_Simps: NAMED_THMS
    85   val set_termination_prover : (Proof.context -> tactic) -> Context.generic -> Context.generic
    86   val get_termination_prover : Proof.context -> tactic
    87   val store_termination_rule : thm -> Context.generic -> Context.generic
    88   datatype function_config = FunctionConfig of
    89    {sequential: bool,
    90     default: string option,
    91     domintros: bool,
    92     partials: bool}
    93   val default_config : function_config
    94   val split_def : Proof.context -> (string -> 'a) -> term ->
    95     string * (string * typ) list * term list * term list * term
    96   val check_defs : Proof.context -> ((string * typ) * 'a) list -> term list -> unit
    97   type fixes = ((string * typ) * mixfix) list
    98   type 'a spec = (Attrib.binding * 'a list) list
    99   type preproc = function_config -> Proof.context -> fixes -> term spec ->
   100     (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
   101   val fname_of : term -> string
   102   val mk_case_names : int -> string -> int -> string list
   103   val empty_preproc : (Proof.context -> ((string * typ) * mixfix) list -> term list -> 'c) -> preproc
   104   val get_preproc: Proof.context -> preproc
   105   val set_preproc: preproc -> Context.generic -> Context.generic
   106   val function_parser : function_config ->
   107     ((function_config * (binding * string option * mixfix) list) * (Attrib.binding * string) list) parser
   108 end
   109 
   110 structure Function_Common : FUNCTION_COMMON =
   111 struct
   112 
   113 open Function_Data
   114 
   115 local open Function_Lib in
   116 
   117 (* Profiling *)
   118 val profile = Unsynchronized.ref false;
   119 
   120 fun PROFILE msg = if !profile then timeap_msg msg else I
   121 
   122 val acc_const_name = @{const_name Wellfounded.accp}
   123 fun mk_acc domT R =
   124   Const (acc_const_name, (domT --> domT --> HOLogic.boolT) --> domT --> HOLogic.boolT) $ R 
   125 
   126 val function_name = suffix "C"
   127 val graph_name = suffix "_graph"
   128 val rel_name = suffix "_rel"
   129 val dom_name = suffix "_dom"
   130 
   131 (* Termination rules *)
   132 
   133 (* FIXME just one data slot (record) per program unit *)
   134 structure TerminationRule = Generic_Data
   135 (
   136   type T = thm list
   137   val empty = []
   138   val extend = I
   139   val merge = Thm.merge_thms
   140 );
   141 
   142 val get_termination_rules = TerminationRule.get
   143 val store_termination_rule = TerminationRule.map o cons
   144 val apply_termination_rule = resolve_tac o get_termination_rules o Context.Proof
   145 
   146 
   147 (* Function definition result data *)
   148 
   149 datatype function_result = FunctionResult of
   150  {fs: term list,
   151   G: term,
   152   R: term,
   153   dom: term,
   154   psimps : thm list,
   155   simple_pinducts : thm list,
   156   cases : thm list,
   157   pelims : thm list list,
   158   termination : thm,
   159   domintros : thm list option}
   160 
   161 fun transform_function_data ({add_simps, case_names, fnames, fs, R, dom, psimps, pinducts,
   162   simps, inducts, termination, defname, is_partial, cases, pelims, elims} : info) phi =
   163     let
   164       val term = Morphism.term phi
   165       val thm = Morphism.thm phi
   166       val fact = Morphism.fact phi
   167       val name = Binding.name_of o Morphism.binding phi o Binding.name
   168     in
   169       { add_simps = add_simps, case_names = case_names, fnames = fnames,
   170         fs = map term fs, R = term R, dom = term dom, psimps = fact psimps,
   171         pinducts = fact pinducts, simps = Option.map fact simps,
   172         inducts = Option.map fact inducts, termination = thm termination,
   173         defname = name defname, is_partial=is_partial, cases = fact cases,
   174         elims = Option.map (map fact) elims, pelims = map fact pelims }
   175     end
   176 
   177 (* FIXME just one data slot (record) per program unit *)
   178 structure FunctionData = Generic_Data
   179 (
   180   type T = (term * info) Item_Net.T;
   181   val empty : T = Item_Net.init (op aconv o pairself fst) (single o fst);
   182   val extend = I;
   183   fun merge tabs : T = Item_Net.merge tabs;
   184 )
   185 
   186 val get_function = FunctionData.get o Context.Proof;
   187 
   188 fun lift_morphism thy f =
   189   let
   190     fun term t = Thm.term_of (Drule.cterm_rule f (Thm.cterm_of thy t))
   191   in
   192     Morphism.thm_morphism f $> Morphism.term_morphism term
   193     $> Morphism.typ_morphism (Logic.type_map term)
   194   end
   195 
   196 fun import_function_data t ctxt =
   197   let
   198     val thy = Proof_Context.theory_of ctxt
   199     val ct = cterm_of thy t
   200     val inst_morph = lift_morphism thy o Thm.instantiate
   201 
   202     fun match (trm, data) =
   203       SOME (transform_function_data data (inst_morph (Thm.match (cterm_of thy trm, ct))))
   204       handle Pattern.MATCH => NONE
   205   in
   206     get_first match (Item_Net.retrieve (get_function ctxt) t)
   207   end
   208 
   209 fun import_last_function ctxt =
   210   case Item_Net.content (get_function ctxt) of
   211     [] => NONE
   212   | (t, _) :: _ =>
   213     let
   214       val ([t'], ctxt') = Variable.import_terms true [t] ctxt
   215     in
   216       import_function_data t' ctxt'
   217     end
   218 
   219 fun add_function_data (data : info as {fs, termination, ...}) =
   220   FunctionData.map (fold (fn f => Item_Net.update (f, data)) fs)
   221   #> store_termination_rule termination
   222 
   223 
   224 (* Simp rules for termination proofs *)
   225 
   226 structure Termination_Simps = Named_Thms
   227 (
   228   val name = @{binding termination_simp}
   229   val description = "simplification rules for termination proofs"
   230 )
   231 
   232 
   233 (* Default Termination Prover *)
   234 
   235 (* FIXME just one data slot (record) per program unit *)
   236 structure TerminationProver = Generic_Data
   237 (
   238   type T = Proof.context -> tactic
   239   val empty = (fn _ => error "Termination prover not configured")
   240   val extend = I
   241   fun merge (a, _) = a
   242 )
   243 
   244 val set_termination_prover = TerminationProver.put
   245 fun get_termination_prover ctxt = TerminationProver.get (Context.Proof ctxt) ctxt
   246 
   247 
   248 (* Configuration management *)
   249 datatype function_opt
   250   = Sequential
   251   | Default of string
   252   | DomIntros
   253   | No_Partials
   254 
   255 datatype function_config = FunctionConfig of
   256  {sequential: bool,
   257   default: string option,
   258   domintros: bool,
   259   partials: bool}
   260 
   261 fun apply_opt Sequential (FunctionConfig {sequential, default, domintros, partials}) =
   262     FunctionConfig {sequential=true, default=default, domintros=domintros, partials=partials}
   263   | apply_opt (Default d) (FunctionConfig {sequential, default, domintros, partials}) =
   264     FunctionConfig {sequential=sequential, default=SOME d, domintros=domintros, partials=partials}
   265   | apply_opt DomIntros (FunctionConfig {sequential, default, domintros, partials}) =
   266     FunctionConfig {sequential=sequential, default=default, domintros=true, partials=partials}
   267   | apply_opt No_Partials (FunctionConfig {sequential, default, domintros, partials}) =
   268     FunctionConfig {sequential=sequential, default=default, domintros=domintros, partials=false}
   269 
   270 val default_config =
   271   FunctionConfig { sequential=false, default=NONE,
   272     domintros=false, partials=true}
   273 
   274 
   275 (* Analyzing function equations *)
   276 
   277 fun split_def ctxt check_head geq =
   278   let
   279     fun input_error msg = cat_lines [msg, Syntax.string_of_term ctxt geq]
   280     val qs = Term.strip_qnt_vars "all" geq
   281     val imp = Term.strip_qnt_body "all" geq
   282     val (gs, eq) = Logic.strip_horn imp
   283 
   284     val (f_args, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop eq)
   285       handle TERM _ => error (input_error "Not an equation")
   286 
   287     val (head, args) = strip_comb f_args
   288 
   289     val fname = fst (dest_Free head) handle TERM _ => ""
   290     val _ = check_head fname
   291   in
   292     (fname, qs, gs, args, rhs)
   293   end
   294 
   295 (* Check for all sorts of errors in the input *)
   296 fun check_defs ctxt fixes eqs =
   297   let
   298     val fnames = map (fst o fst) fixes
   299 
   300     fun check geq =
   301       let
   302         fun input_error msg = error (cat_lines [msg, Syntax.string_of_term ctxt geq])
   303 
   304         fun check_head fname =
   305           member (op =) fnames fname orelse
   306           input_error ("Illegal equation head. Expected " ^ commas_quote fnames)
   307 
   308         val (fname, qs, gs, args, rhs) = split_def ctxt check_head geq
   309 
   310         val _ = length args > 0 orelse input_error "Function has no arguments:"
   311 
   312         fun add_bvs t is = add_loose_bnos (t, 0, is)
   313         val rvs = (subtract (op =) (fold add_bvs args []) (add_bvs rhs []))
   314                     |> map (fst o nth (rev qs))
   315 
   316         val _ = null rvs orelse input_error
   317           ("Variable" ^ plural " " "s " rvs ^ commas_quote rvs ^
   318            " occur" ^ plural "s" "" rvs ^ " on right hand side only:")
   319 
   320         val _ = forall (not o Term.exists_subterm
   321           (fn Free (n, _) => member (op =) fnames n | _ => false)) (gs @ args)
   322           orelse input_error "Defined function may not occur in premises or arguments"
   323 
   324         val freeargs = map (fn t => subst_bounds (rev (map Free qs), t)) args
   325         val funvars = filter (fn q => exists (exists_subterm (fn (Free q') $ _ => q = q' | _ => false)) freeargs) qs
   326         val _ = null funvars orelse (warning (cat_lines
   327           ["Bound variable" ^ plural " " "s " funvars ^
   328           commas_quote (map fst funvars) ^ " occur" ^ plural "s" "" funvars ^
   329           " in function position.", "Misspelled constructor???"]); true)
   330       in
   331         (fname, length args)
   332       end
   333 
   334     val grouped_args = AList.group (op =) (map check eqs)
   335     val _ = grouped_args
   336       |> map (fn (fname, ars) =>
   337         length (distinct (op =) ars) = 1
   338         orelse error ("Function " ^ quote fname ^
   339           " has different numbers of arguments in different equations"))
   340 
   341     val not_defined = subtract (op =) (map fst grouped_args) fnames
   342     val _ = null not_defined
   343       orelse error ("No defining equations for function" ^
   344         plural " " "s " not_defined ^ commas_quote not_defined)
   345 
   346     fun check_sorts ((fname, fT), _) =
   347       Sorts.of_sort (Sign.classes_of (Proof_Context.theory_of ctxt)) (fT, HOLogic.typeS)
   348       orelse error (cat_lines
   349       ["Type of " ^ quote fname ^ " is not of sort " ^ quote "type" ^ ":",
   350        Syntax.string_of_typ (Config.put show_sorts true ctxt) fT])
   351 
   352     val _ = map check_sorts fixes
   353   in
   354     ()
   355   end
   356 
   357 (* Preprocessors *)
   358 
   359 type fixes = ((string * typ) * mixfix) list
   360 type 'a spec = (Attrib.binding * 'a list) list
   361 type preproc = function_config -> Proof.context -> fixes -> term spec ->
   362   (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
   363 
   364 val fname_of = fst o dest_Free o fst o strip_comb o fst o HOLogic.dest_eq o
   365   HOLogic.dest_Trueprop o Logic.strip_imp_concl o snd o dest_all_all
   366 
   367 fun mk_case_names i "" k = mk_case_names i (string_of_int (i + 1)) k
   368   | mk_case_names _ n 0 = []
   369   | mk_case_names _ n 1 = [n]
   370   | mk_case_names _ n k = map (fn i => n ^ "_" ^ string_of_int i) (1 upto k)
   371 
   372 fun empty_preproc check (_: function_config) (ctxt: Proof.context) (fixes: fixes) spec =
   373   let
   374     val (bnds, tss) = split_list spec
   375     val ts = flat tss
   376     val _ = check ctxt fixes ts
   377     val fnames = map (fst o fst) fixes
   378     val indices = map (fn eq => find_index (curry op = (fname_of eq)) fnames) ts
   379 
   380     fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1) 
   381       (indices ~~ xs) |> map (map snd)
   382 
   383     (* using theorem names for case name currently disabled *)
   384     val cnames = map_index (fn (i, _) => mk_case_names i "" 1) bnds |> flat
   385   in
   386     (ts, curry op ~~ bnds o Library.unflat tss, sort, cnames)
   387   end
   388 
   389 (* FIXME just one data slot (record) per program unit *)
   390 structure Preprocessor = Generic_Data
   391 (
   392   type T = preproc
   393   val empty : T = empty_preproc check_defs
   394   val extend = I
   395   fun merge (a, _) = a
   396 )
   397 
   398 val get_preproc = Preprocessor.get o Context.Proof
   399 val set_preproc = Preprocessor.map o K
   400 
   401 
   402 
   403 local
   404   val option_parser = Parse.group (fn () => "option")
   405     ((Parse.reserved "sequential" >> K Sequential)
   406      || ((Parse.reserved "default" |-- Parse.term) >> Default)
   407      || (Parse.reserved "domintros" >> K DomIntros)
   408      || (Parse.reserved "no_partials" >> K No_Partials))
   409 
   410   fun config_parser default =
   411     (Scan.optional (@{keyword "("} |-- Parse.!!! (Parse.list1 option_parser) --| @{keyword ")"}) [])
   412      >> (fn opts => fold apply_opt opts default)
   413 in
   414   fun function_parser default_cfg =
   415       config_parser default_cfg -- Parse.fixes -- Parse_Spec.where_alt_specs
   416 end
   417 
   418 
   419 end
   420 end