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