(* Title: Pure/Isar/rule_cases.ML ID: $Id: rule_cases.ML,v 1.37 2005/09/13 20:19:46 wenzelm Exp $ Author: Markus Wenzel, TU Muenchen Manage local contexts of rules. *) signature RULE_CASES = sig val consumes: int -> 'a attribute val consumes_default: int -> 'a attribute val name: string list -> thm -> thm val case_names: string list -> 'a attribute val save: thm -> thm -> thm val get: thm -> string list * int val add: thm -> thm * (string list * int) type T val make: bool -> term option -> theory * term -> string list -> (string * T option) list val simple: bool -> theory * term -> string -> string * T option val rename_params: string list list -> thm -> thm val params: string list list -> 'a attribute type tactic val NO_CASES: Tactical.tactic -> tactic end; structure RuleCases: RULE_CASES = struct (* names *) val consumes_tagN = "consumes"; val cases_tagN = "cases"; val case_conclN = "case"; val case_hypsN = "hyps"; val case_premsN = "prems"; (* number of consumed facts *) fun lookup_consumes thm = let fun err () = raise THM ("Malformed 'consumes' tag of theorem", 0, [thm]) in (case AList.lookup (op =) (Thm.tags_of_thm thm) (consumes_tagN) of NONE => NONE | SOME [s] => (case Syntax.read_nat s of SOME n => SOME n | _ => err ()) | _ => err ()) end; fun put_consumes NONE th = th | put_consumes (SOME n) th = th |> Drule.untag_rule consumes_tagN |> Drule.tag_rule (consumes_tagN, [Library.string_of_int n]); val save_consumes = put_consumes o lookup_consumes; fun consumes n x = Drule.rule_attribute (K (put_consumes (SOME n))) x; fun consumes_default n x = if Library.is_some (lookup_consumes (#2 x)) then x else consumes n x; (* case names *) fun put_case_names NONE thm = thm | put_case_names (SOME names) thm = thm |> Drule.untag_rule cases_tagN |> Drule.tag_rule (cases_tagN, names); fun lookup_case_names thm = AList.lookup (op =) (Thm.tags_of_thm thm) cases_tagN; val save_case_names = put_case_names o lookup_case_names; val name = put_case_names o SOME; fun case_names ss = Drule.rule_attribute (K (name ss)); (* access hints *) fun save thm = save_case_names thm o save_consumes thm; fun get thm = let val n = if_none (lookup_consumes thm) 0; val ss = (case lookup_case_names thm of NONE => map Library.string_of_int (1 upto (Thm.nprems_of thm - n)) | SOME ss => ss); in (ss, n) end; fun add thm = (thm, get thm); (* prepare cases *) type T = {fixes: (string * typ) list, assumes: (string * term list) list, binds: (indexname * term option) list}; fun unskolem x = (case try Syntax.dest_skolem x of SOME x' => x' | NONE => x); fun prep_case is_open thy (split, raw_prop) name = let val prop = Drule.norm_hhf thy raw_prop; val xs = map (apfst unskolem) (Logic.strip_params prop); val rename = if is_open then I else map (apfst Syntax.internal); val named_xs = (case split of NONE => rename xs | SOME t => let val (us, vs) = splitAt (length (Logic.strip_params t), xs) in rename us @ vs end); val asms = map (curry Term.list_abs named_xs) (Logic.strip_assums_hyp prop); val named_asms = (case split of NONE => [("", asms)] | SOME t => let val (hyps, prems) = splitAt (length (Logic.strip_assums_hyp t), asms) in [(case_hypsN, hyps), (case_premsN, prems)] end); val concl = Term.list_abs (named_xs, Logic.strip_assums_concl prop); val bind = ((case_conclN, 0), SOME (ObjectLogic.drop_judgment thy concl)); in (name, SOME {fixes = named_xs, assumes = named_asms, binds = [bind]}) end; fun make is_open split (thy, prop) names = let val nprems = Logic.count_prems (prop, 0); fun add_case name (cases, i) = ((case try (fn () => (Option.map (curry Logic.nth_prem i) split, Logic.nth_prem (i, prop))) () of NONE => (name, NONE) | SOME sp => prep_case is_open thy sp name) :: cases, i - 1); in fold_rev add_case (Library.drop (length names - nprems, names)) ([], length names) |> #1 end; fun simple is_open (thy, prop) = prep_case is_open thy (NONE, prop); (* params *) fun rename_params xss thm = foldln Thm.rename_params_rule xss thm |> save thm; fun params xss = Drule.rule_attribute (K (rename_params xss)); (* tactics with cases *) type tactic = thm -> (thm * (string * T option) list) Seq.seq; fun NO_CASES tac = Seq.map (rpair []) o tac; end; val NO_CASES = RuleCases.NO_CASES;