src/HOL/Tools/function_package/fundef_common.ML
author wenzelm
Tue, 17 Mar 2009 14:12:43 +0100
changeset 30562 0cc3b7f03ade
parent 30515 4120fc59dd85
child 30786 5b7a5a05c7aa
permissions -rw-r--r--
adapted to general Item_Net;
     1 (*  Title:      HOL/Tools/function_package/fundef_common.ML
     2     Author:     Alexander Krauss, TU Muenchen
     3 
     4 A package for general recursive function definitions. 
     5 Common definitions and other infrastructure.
     6 *)
     7 
     8 structure FundefCommon =
     9 struct
    10 
    11 local open FundefLib in
    12 
    13 (* Profiling *)
    14 val profile = ref false;
    15 
    16 fun PROFILE msg = if !profile then timeap_msg msg else I
    17 
    18 
    19 val acc_const_name = @{const_name "accp"}
    20 fun mk_acc domT R =
    21     Const (acc_const_name, (domT --> domT --> HOLogic.boolT) --> domT --> HOLogic.boolT) $ R 
    22 
    23 val function_name = suffix "C"
    24 val graph_name = suffix "_graph"
    25 val rel_name = suffix "_rel"
    26 val dom_name = suffix "_dom"
    27 
    28 (* Termination rules *)
    29 
    30 structure TerminationRule = GenericDataFun
    31 (
    32   type T = thm list
    33   val empty = []
    34   val extend = I
    35   fun merge _ = Thm.merge_thms
    36 );
    37 
    38 val get_termination_rules = TerminationRule.get
    39 val store_termination_rule = TerminationRule.map o cons
    40 val apply_termination_rule = resolve_tac o get_termination_rules o Context.Proof
    41 
    42 
    43 (* Function definition result data *)
    44 
    45 datatype fundef_result =
    46   FundefResult of
    47      {
    48       fs: term list,
    49       G: term,
    50       R: term,
    51 
    52       psimps : thm list, 
    53       trsimps : thm list option, 
    54 
    55       simple_pinducts : thm list, 
    56       cases : thm,
    57       termination : thm,
    58       domintros : thm list option
    59      }
    60 
    61 
    62 datatype fundef_context_data =
    63   FundefCtxData of
    64      {
    65       defname : string,
    66 
    67       (* contains no logical entities: invariant under morphisms *)
    68       add_simps : (string -> string) -> string -> Attrib.src list -> thm list 
    69                   -> local_theory -> thm list * local_theory,
    70       case_names : string list,
    71 
    72       fs : term list,
    73       R : term,
    74       
    75       psimps: thm list,
    76       pinducts: thm list,
    77       termination: thm
    78      }
    79 
    80 fun morph_fundef_data (FundefCtxData {add_simps, case_names, fs, R, 
    81                                       psimps, pinducts, termination, defname}) phi =
    82     let
    83       val term = Morphism.term phi val thm = Morphism.thm phi val fact = Morphism.fact phi
    84       val name = Binding.name_of o Morphism.binding phi o Binding.name
    85     in
    86       FundefCtxData { add_simps = add_simps, case_names = case_names,
    87                       fs = map term fs, R = term R, psimps = fact psimps, 
    88                       pinducts = fact pinducts, termination = thm termination,
    89                       defname = name defname }
    90     end
    91 
    92 structure FundefData = GenericDataFun
    93 (
    94   type T = (term * fundef_context_data) Item_Net.T;
    95   val empty = Item_Net.init
    96     (op aconv o pairself fst : (term * fundef_context_data) * (term * fundef_context_data) -> bool)
    97     fst;
    98   val copy = I;
    99   val extend = I;
   100   fun merge _ (tab1, tab2) = Item_Net.merge (tab1, tab2)
   101 );
   102 
   103 val get_fundef = FundefData.get o Context.Proof;
   104 
   105 
   106 (* Generally useful?? *)
   107 fun lift_morphism thy f = 
   108     let 
   109       val term = Drule.term_rule thy f
   110     in
   111       Morphism.thm_morphism f $> Morphism.term_morphism term 
   112        $> Morphism.typ_morphism (Logic.type_map term)
   113     end
   114 
   115 fun import_fundef_data t ctxt =
   116     let
   117       val thy = ProofContext.theory_of ctxt
   118       val ct = cterm_of thy t
   119       val inst_morph = lift_morphism thy o Thm.instantiate 
   120 
   121       fun match (trm, data) = 
   122           SOME (morph_fundef_data data (inst_morph (Thm.match (cterm_of thy trm, ct))))
   123           handle Pattern.MATCH => NONE
   124     in 
   125       get_first match (Item_Net.retrieve (get_fundef ctxt) t)
   126     end
   127 
   128 fun import_last_fundef ctxt =
   129     case Item_Net.content (get_fundef ctxt) of
   130       [] => NONE
   131     | (t, data) :: _ =>
   132       let 
   133         val ([t'], ctxt') = Variable.import_terms true [t] ctxt
   134       in
   135         import_fundef_data t' ctxt'
   136       end
   137 
   138 val all_fundef_data = Item_Net.content o get_fundef
   139 
   140 fun add_fundef_data (data as FundefCtxData {fs, termination, ...}) =
   141     FundefData.map (fold (fn f => Item_Net.insert (f, data)) fs)
   142     #> store_termination_rule termination
   143 
   144 
   145 (* Simp rules for termination proofs *)
   146 
   147 structure TerminationSimps = NamedThmsFun
   148 (
   149   val name = "termination_simp" 
   150   val description = "Simplification rule for termination proofs"
   151 );
   152 
   153 
   154 (* Default Termination Prover *)
   155 
   156 structure TerminationProver = GenericDataFun
   157 (
   158   type T = Proof.context -> Proof.method
   159   val empty = (fn _ => error "Termination prover not configured")
   160   val extend = I
   161   fun merge _ (a,b) = b (* FIXME *)
   162 );
   163 
   164 val set_termination_prover = TerminationProver.put
   165 val get_termination_prover = TerminationProver.get o Context.Proof
   166 
   167 
   168 (* Configuration management *)
   169 datatype fundef_opt 
   170   = Sequential
   171   | Default of string
   172   | DomIntros
   173   | Tailrec
   174 
   175 datatype fundef_config
   176   = FundefConfig of
   177    {
   178     sequential: bool,
   179     default: string,
   180     domintros: bool,
   181     tailrec: bool
   182    }
   183 
   184 fun apply_opt Sequential (FundefConfig {sequential, default, domintros,tailrec}) = 
   185     FundefConfig {sequential=true, default=default, domintros=domintros, tailrec=tailrec}
   186   | apply_opt (Default d) (FundefConfig {sequential, default, domintros,tailrec}) = 
   187     FundefConfig {sequential=sequential, default=d, domintros=domintros, tailrec=tailrec}
   188   | apply_opt DomIntros (FundefConfig {sequential, default, domintros,tailrec}) =
   189     FundefConfig {sequential=sequential, default=default, domintros=true,tailrec=tailrec}
   190   | apply_opt Tailrec (FundefConfig {sequential, default, domintros,tailrec}) =
   191     FundefConfig {sequential=sequential, default=default, domintros=domintros,tailrec=true}
   192 
   193 val default_config =
   194   FundefConfig { sequential=false, default="%x. undefined" (*FIXME dynamic scoping*), 
   195                  domintros=false, tailrec=false }
   196 
   197 
   198 (* Analyzing function equations *)
   199 
   200 fun split_def ctxt geq =
   201     let
   202       fun input_error msg = cat_lines [msg, Syntax.string_of_term ctxt geq]
   203       val qs = Term.strip_qnt_vars "all" geq
   204       val imp = Term.strip_qnt_body "all" geq
   205       val (gs, eq) = Logic.strip_horn imp
   206 
   207       val (f_args, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop eq)
   208           handle TERM _ => error (input_error "Not an equation")
   209 
   210       val (head, args) = strip_comb f_args
   211 
   212       val fname = fst (dest_Free head)
   213           handle TERM _ => error (input_error "Head symbol must not be a bound variable")
   214     in
   215       (fname, qs, gs, args, rhs)
   216     end
   217 
   218 exception ArgumentCount of string
   219 
   220 fun mk_arities fqgars =
   221     let fun f (fname, _, _, args, _) arities =
   222             let val k = length args
   223             in
   224               case Symtab.lookup arities fname of
   225                 NONE => Symtab.update (fname, k) arities
   226               | SOME i => (if i = k then arities else raise ArgumentCount fname)
   227             end
   228     in
   229       fold f fqgars Symtab.empty
   230     end
   231 
   232 
   233 (* Check for all sorts of errors in the input *)
   234 fun check_defs ctxt fixes eqs =
   235     let
   236       val fnames = map (fst o fst) fixes
   237                                 
   238       fun check geq = 
   239           let
   240             fun input_error msg = error (cat_lines [msg, Syntax.string_of_term ctxt geq])
   241                                   
   242             val fqgar as (fname, qs, gs, args, rhs) = split_def ctxt geq
   243                                  
   244             val _ = fname mem fnames 
   245                     orelse input_error 
   246                              ("Head symbol of left hand side must be " 
   247                               ^ plural "" "one out of " fnames ^ commas_quote fnames)
   248                                             
   249             fun add_bvs t is = add_loose_bnos (t, 0, is)
   250             val rvs = (add_bvs rhs [] \\ fold add_bvs args [])
   251                         |> map (fst o nth (rev qs))
   252                       
   253             val _ = null rvs orelse input_error 
   254                         ("Variable" ^ plural " " "s " rvs ^ commas_quote rvs
   255                          ^ " occur" ^ plural "s" "" rvs ^ " on right hand side only:")
   256                                     
   257             val _ = forall (not o Term.exists_subterm 
   258                              (fn Free (n, _) => n mem fnames | _ => false)) (gs @ args)
   259                     orelse input_error "Defined function may not occur in premises or arguments"
   260 
   261             val freeargs = map (fn t => subst_bounds (rev (map Free qs), t)) args
   262             val funvars = filter (fn q => exists (exists_subterm (fn (Free q') $ _ => q = q' | _ => false)) freeargs) qs
   263             val _ = null funvars
   264                     orelse (warning (cat_lines 
   265                     ["Bound variable" ^ plural " " "s " funvars 
   266                      ^ commas_quote (map fst funvars) ^  
   267                      " occur" ^ plural "s" "" funvars ^ " in function position.",  
   268                      "Misspelled constructor???"]); true)
   269           in
   270             fqgar
   271           end
   272           
   273       val _ = mk_arities (map check eqs)
   274           handle ArgumentCount fname => 
   275                  error ("Function " ^ quote fname ^ 
   276                         " has different numbers of arguments in different equations")
   277 
   278       fun check_sorts ((fname, fT), _) =
   279           Sorts.of_sort (Sign.classes_of (ProofContext.theory_of ctxt)) (fT, HOLogic.typeS)
   280           orelse error (cat_lines 
   281           ["Type of " ^ quote fname ^ " is not of sort " ^ quote "type" ^ ":",
   282            setmp show_sorts true (Syntax.string_of_typ ctxt) fT])
   283 
   284       val _ = map check_sorts fixes
   285     in
   286       ()
   287     end
   288 
   289 (* Preprocessors *)
   290 
   291 type fixes = ((string * typ) * mixfix) list
   292 type 'a spec = ((bstring * Attrib.src list) * 'a list) list
   293 type preproc = fundef_config -> bool list -> Proof.context -> fixes -> term spec 
   294                -> (term list * (thm list -> thm spec) * (thm list -> thm list list) * string list)
   295 
   296 val fname_of = fst o dest_Free o fst o strip_comb o fst 
   297  o HOLogic.dest_eq o HOLogic.dest_Trueprop o Logic.strip_imp_concl o snd o dest_all_all
   298 
   299 fun mk_case_names i "" k = mk_case_names i (string_of_int (i + 1)) k
   300   | mk_case_names _ n 0 = []
   301   | mk_case_names _ n 1 = [n]
   302   | mk_case_names _ n k = map (fn i => n ^ "_" ^ string_of_int i) (1 upto k)
   303 
   304 fun empty_preproc check _ _ ctxt fixes spec =
   305     let 
   306       val (nas,tss) = split_list spec
   307       val ts = flat tss
   308       val _ = check ctxt fixes ts
   309       val fnames = map (fst o fst) fixes
   310       val indices = map (fn eq => find_index (curry op = (fname_of eq)) fnames) ts
   311 
   312       fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1) 
   313                                    (indices ~~ xs)
   314                         |> map (map snd)
   315 
   316       (* using theorem names for case name currently disabled *)
   317       val cnames = map_index (fn (i, (n,_)) => mk_case_names i "" 1) nas |> flat
   318     in
   319       (ts, curry op ~~ nas o Library.unflat tss, sort, cnames)
   320     end
   321 
   322 structure Preprocessor = GenericDataFun
   323 (
   324   type T = preproc
   325   val empty : T = empty_preproc check_defs
   326   val extend = I
   327   fun merge _ (a, _) = a
   328 );
   329 
   330 val get_preproc = Preprocessor.get o Context.Proof
   331 val set_preproc = Preprocessor.map o K
   332 
   333 
   334 
   335 local 
   336   structure P = OuterParse and K = OuterKeyword
   337 
   338   val option_parser = 
   339       P.group "option" ((P.reserved "sequential" >> K Sequential)
   340                     || ((P.reserved "default" |-- P.term) >> Default)
   341                     || (P.reserved "domintros" >> K DomIntros)
   342                     || (P.reserved "tailrec" >> K Tailrec))
   343 
   344   fun config_parser default = 
   345       (Scan.optional (P.$$$ "(" |-- P.!!! (P.list1 option_parser) --| P.$$$ ")") [])
   346         >> (fn opts => fold apply_opt opts default)
   347 
   348   val otherwise = P.$$$ "(" |-- P.$$$ "otherwise" --| P.$$$ ")"
   349 
   350   fun pipe_error t = 
   351   P.!!! (Scan.fail_with (K (cat_lines ["Equations must be separated by " ^ quote "|", quote t])))
   352 
   353   val statement_ow = 
   354    SpecParse.opt_thm_name ":" -- (P.prop -- Scan.optional (otherwise >> K true) false)
   355     --| Scan.ahead ((P.term :-- pipe_error) || Scan.succeed ("",""))
   356 
   357   val statements_ow = P.enum1 "|" statement_ow
   358 
   359   val flags_statements = statements_ow
   360                          >> (fn sow => (map (snd o snd) sow, map (apsnd fst) sow))
   361 in
   362   fun fundef_parser default_cfg = 
   363       config_parser default_cfg -- P.fixes --| P.where_ -- flags_statements
   364 end
   365 
   366 
   367 end
   368 end
   369