author | kleing |
Tue, 13 May 2003 08:59:21 +0200 | |
changeset 14024 | 213dcc39358f |
parent 13668 | 11397ea8b438 |
child 14404 | 4952c5a92e04 |
permissions | -rw-r--r-- |
8364 | 1 |
(* Title: Pure/Isar/rule_cases.ML |
2 |
ID: $Id$ |
|
3 |
Author: Markus Wenzel, TU Muenchen |
|
8807 | 4 |
License: GPL (GNU GENERAL PUBLIC LICENSE) |
8364 | 5 |
|
6 |
Manage local contexts of rules. |
|
7 |
*) |
|
8 |
||
9 |
signature RULE_CASES = |
|
10 |
sig |
|
10530 | 11 |
val consumes: int -> 'a attribute |
12 |
val consumes_default: int -> 'a attribute |
|
8364 | 13 |
val name: string list -> thm -> thm |
8427 | 14 |
val case_names: string list -> 'a attribute |
12761 | 15 |
val save: thm -> thm -> thm |
10530 | 16 |
val get: thm -> string list * int |
17 |
val add: thm -> thm * (string list * int) |
|
10811 | 18 |
type T |
12166 | 19 |
val empty: T |
13596 | 20 |
val hhf_nth_subgoal: Sign.sg -> int * term -> term |
21 |
val make: int option -> term option -> Sign.sg * term -> string list -> (string * T) list |
|
8427 | 22 |
val rename_params: string list list -> thm -> thm |
8364 | 23 |
val params: string list list -> 'a attribute |
24 |
end; |
|
25 |
||
26 |
structure RuleCases: RULE_CASES = |
|
27 |
struct |
|
28 |
||
10811 | 29 |
(* names *) |
30 |
||
31 |
val consumes_tagN = "consumes"; |
|
32 |
val cases_tagN = "cases"; |
|
33 |
val case_conclN = "case"; |
|
34 |
||
35 |
||
10530 | 36 |
(* number of consumed facts *) |
8364 | 37 |
|
12761 | 38 |
fun lookup_consumes thm = |
10530 | 39 |
let fun err () = raise THM ("Malformed 'consumes' tag of theorem", 0, [thm]) in |
12761 | 40 |
(case Library.assoc (Thm.tags_of_thm thm, consumes_tagN) of |
41 |
None => None |
|
42 |
| Some [s] => (case Syntax.read_nat s of Some n => Some n | _ => err ()) |
|
10530 | 43 |
| _ => err ()) |
44 |
end; |
|
45 |
||
12761 | 46 |
fun put_consumes None th = th |
47 |
| put_consumes (Some n) th = th |
|
48 |
|> Drule.untag_rule consumes_tagN |
|
49 |
|> Drule.tag_rule (consumes_tagN, [Library.string_of_int n]); |
|
10530 | 50 |
|
12761 | 51 |
val save_consumes = put_consumes o lookup_consumes; |
52 |
||
53 |
fun consumes n x = Drule.rule_attribute (K (put_consumes (Some n))) x; |
|
10530 | 54 |
fun consumes_default n x = if Library.is_some (lookup_consumes (#2 x)) then x else consumes n x; |
8364 | 55 |
|
56 |
||
57 |
(* case names *) |
|
58 |
||
12761 | 59 |
fun put_case_names None thm = thm |
60 |
| put_case_names (Some names) thm = |
|
61 |
thm |
|
62 |
|> Drule.untag_rule cases_tagN |
|
63 |
|> Drule.tag_rule (cases_tagN, names); |
|
8364 | 64 |
|
12761 | 65 |
fun lookup_case_names thm = Library.assoc (Thm.tags_of_thm thm, cases_tagN); |
10530 | 66 |
|
12761 | 67 |
val save_case_names = put_case_names o lookup_case_names; |
68 |
val name = put_case_names o Some; |
|
8427 | 69 |
fun case_names ss = Drule.rule_attribute (K (name ss)); |
8364 | 70 |
|
10530 | 71 |
|
72 |
(* access hints *) |
|
73 |
||
12761 | 74 |
fun save thm = save_case_names thm o save_consumes thm; |
75 |
||
76 |
fun get thm = |
|
77 |
let |
|
78 |
val n = if_none (lookup_consumes thm) 0; |
|
79 |
val ss = |
|
80 |
(case lookup_case_names thm of |
|
81 |
None => map Library.string_of_int (1 upto (Thm.nprems_of thm - n)) |
|
82 |
| Some ss => ss); |
|
83 |
in (ss, n) end; |
|
84 |
||
8364 | 85 |
fun add thm = (thm, get thm); |
10530 | 86 |
|
8364 | 87 |
|
88 |
(* prepare cases *) |
|
89 |
||
13425
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
90 |
type T = |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
91 |
{fixes: (string * typ) list, |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
92 |
assumes: (string * term list) list, |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
93 |
binds: (indexname * term option) list}; |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
94 |
|
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
95 |
val hypsN = "hyps"; |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
96 |
val premsN = "prems"; |
10530 | 97 |
|
12166 | 98 |
val empty = {fixes = [], assumes = [], binds = []}; |
99 |
||
13596 | 100 |
fun nth_subgoal(i,prop) = |
13668 | 101 |
hd (#1 (Logic.strip_prems (i, [], prop))); |
13596 | 102 |
|
103 |
fun hhf_nth_subgoal sg = Drule.norm_hhf sg o nth_subgoal |
|
104 |
||
105 |
(* open_params = None |
|
106 |
==> all parameters are "open", ie their default names are used. |
|
107 |
open_params = Some k |
|
108 |
==> only the last k parameters, the ones coming from the original |
|
109 |
goal, not from the induction rule, are "open" |
|
110 |
*) |
|
111 |
fun prep_case open_params split sg prop name i = |
|
8364 | 112 |
let |
13596 | 113 |
val Bi = hhf_nth_subgoal sg (i,prop); |
114 |
val all_xs = Logic.strip_params Bi |
|
115 |
val n = length all_xs - (if_none open_params 0) |
|
13629 | 116 |
val (ind_xs, goal_xs) = splitAt(n,all_xs) |
13596 | 117 |
val rename = if is_none open_params then I else apfst Syntax.internal |
118 |
val xs = map rename ind_xs @ goal_xs |
|
10811 | 119 |
val asms = map (curry Term.list_abs xs) (Logic.strip_assums_hyp Bi); |
13425
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
120 |
val named_asms = |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
121 |
(case split of None => [("", asms)] |
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
122 |
| Some t => |
13596 | 123 |
let val h = length (Logic.strip_assums_hyp(nth_subgoal(i,t))) |
13629 | 124 |
val (ps,qs) = splitAt(h, asms) |
125 |
in [(hypsN, ps), (premsN, qs)] end); |
|
10872 | 126 |
val concl = Term.list_abs (xs, Logic.strip_assums_concl Bi); |
12809
787ecc2ac737
RuleCases.make interface based on term instead of thm;
wenzelm
parents:
12761
diff
changeset
|
127 |
val bind = ((case_conclN, 0), Some (ObjectLogic.drop_judgment sg concl)); |
13425
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
128 |
in (name, {fixes = xs, assumes = named_asms, binds = [bind]}) end; |
8364 | 129 |
|
13596 | 130 |
fun make open_params split (sg, prop) names = |
13668 | 131 |
let val nprems = Logic.count_prems (prop, 0) in |
13596 | 132 |
foldr (fn (name, (cases, i)) => (prep_case open_params split sg prop name i :: cases, i - 1)) |
13425
119ae829ad9b
support for split assumptions in cases (hyps vs. prems);
wenzelm
parents:
12809
diff
changeset
|
133 |
(Library.drop (length names - nprems, names), ([], length names)) |> #1 |
10811 | 134 |
end; |
8364 | 135 |
|
136 |
||
8427 | 137 |
(* params *) |
8364 | 138 |
|
11002 | 139 |
fun rename_params xss thm = foldln Thm.rename_params_rule xss thm |
10530 | 140 |
|> save thm; |
8364 | 141 |
|
142 |
fun params xss = Drule.rule_attribute (K (rename_params xss)); |
|
143 |
||
144 |
end; |