1 (* Title: HOL/Tools/Function/function_common.ML
2 Author: Alexander Krauss, TU Muenchen
4 Common definitions and other infrastructure for the function package.
7 signature FUNCTION_DATA =
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,
17 case_names : string list,
23 simps : thm list option,
24 inducts : thm list option,
27 pelims: thm list list,
28 elims: thm list list option}
32 structure Function_Data : FUNCTION_DATA =
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,
42 case_names : string list,
48 simps : thm list option,
49 inducts : thm list option,
52 pelims : thm list list,
53 elims : thm list list option}
57 signature FUNCTION_COMMON =
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
74 simple_pinducts : thm list,
76 pelims : thm list list,
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
90 default: string option,
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
110 structure Function_Common : FUNCTION_COMMON =
115 local open Function_Lib in
118 val profile = Unsynchronized.ref false;
120 fun PROFILE msg = if !profile then timeap_msg msg else I
122 val acc_const_name = @{const_name Wellfounded.accp}
124 Const (acc_const_name, (domT --> domT --> HOLogic.boolT) --> domT --> HOLogic.boolT) $ R
126 val function_name = suffix "C"
127 val graph_name = suffix "_graph"
128 val rel_name = suffix "_rel"
129 val dom_name = suffix "_dom"
131 (* Termination rules *)
133 (* FIXME just one data slot (record) per program unit *)
134 structure TerminationRule = Generic_Data
139 val merge = Thm.merge_thms
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
147 (* Function definition result data *)
149 datatype function_result = FunctionResult of
155 simple_pinducts : thm list,
157 pelims : thm list list,
159 domintros : thm list option}
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 =
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
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 }
177 (* FIXME just one data slot (record) per program unit *)
178 structure FunctionData = Generic_Data
180 type T = (term * info) Item_Net.T;
181 val empty : T = Item_Net.init (op aconv o pairself fst) (single o fst);
183 fun merge tabs : T = Item_Net.merge tabs;
186 val get_function = FunctionData.get o Context.Proof;
188 fun lift_morphism thy f =
190 fun term t = Thm.term_of (Drule.cterm_rule f (Thm.cterm_of thy t))
192 Morphism.thm_morphism f $> Morphism.term_morphism term
193 $> Morphism.typ_morphism (Logic.type_map term)
196 fun import_function_data t ctxt =
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
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
206 get_first match (Item_Net.retrieve (get_function ctxt) t)
209 fun import_last_function ctxt =
210 case Item_Net.content (get_function ctxt) of
214 val ([t'], ctxt') = Variable.import_terms true [t] ctxt
216 import_function_data t' ctxt'
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
224 (* Simp rules for termination proofs *)
226 structure Termination_Simps = Named_Thms
228 val name = @{binding termination_simp}
229 val description = "simplification rules for termination proofs"
233 (* Default Termination Prover *)
235 (* FIXME just one data slot (record) per program unit *)
236 structure TerminationProver = Generic_Data
238 type T = Proof.context -> tactic
239 val empty = (fn _ => error "Termination prover not configured")
244 val set_termination_prover = TerminationProver.put
245 fun get_termination_prover ctxt = TerminationProver.get (Context.Proof ctxt) ctxt
248 (* Configuration management *)
249 datatype function_opt
255 datatype function_config = FunctionConfig of
257 default: string option,
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}
271 FunctionConfig { sequential=false, default=NONE,
272 domintros=false, partials=true}
275 (* Analyzing function equations *)
277 fun split_def ctxt check_head geq =
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
284 val (f_args, rhs) = HOLogic.dest_eq (HOLogic.dest_Trueprop eq)
285 handle TERM _ => error (input_error "Not an equation")
287 val (head, args) = strip_comb f_args
289 val fname = fst (dest_Free head) handle TERM _ => ""
290 val _ = check_head fname
292 (fname, qs, gs, args, rhs)
295 (* Check for all sorts of errors in the input *)
296 fun check_defs ctxt fixes eqs =
298 val fnames = map (fst o fst) fixes
302 fun input_error msg = error (cat_lines [msg, Syntax.string_of_term ctxt geq])
304 fun check_head fname =
305 member (op =) fnames fname orelse
306 input_error ("Illegal equation head. Expected " ^ commas_quote fnames)
308 val (fname, qs, gs, args, rhs) = split_def ctxt check_head geq
310 val _ = length args > 0 orelse input_error "Function has no arguments:"
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))
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:")
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"
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)
334 val grouped_args = AList.group (op =) (map check eqs)
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"))
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)
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])
352 val _ = map check_sorts fixes
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)
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
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)
372 fun empty_preproc check (_: function_config) (ctxt: Proof.context) (fixes: fixes) spec =
374 val (bnds, tss) = split_list spec
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
380 fun sort xs = partition_list (fn i => fn (j,_) => i = j) 0 (length fnames - 1)
381 (indices ~~ xs) |> map (map snd)
383 (* using theorem names for case name currently disabled *)
384 val cnames = map_index (fn (i, _) => mk_case_names i "" 1) bnds |> flat
386 (ts, curry op ~~ bnds o Library.unflat tss, sort, cnames)
389 (* FIXME just one data slot (record) per program unit *)
390 structure Preprocessor = Generic_Data
393 val empty : T = empty_preproc check_defs
398 val get_preproc = Preprocessor.get o Context.Proof
399 val set_preproc = Preprocessor.map o K
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))
410 fun config_parser default =
411 (Scan.optional (@{keyword "("} |-- Parse.!!! (Parse.list1 option_parser) --| @{keyword ")"}) [])
412 >> (fn opts => fold apply_opt opts default)
414 fun function_parser default_cfg =
415 config_parser default_cfg -- Parse.fixes -- Parse_Spec.where_alt_specs