4 Measurability prover. |
4 Measurability prover. |
5 *) |
5 *) |
6 |
6 |
7 signature MEASURABLE = |
7 signature MEASURABLE = |
8 sig |
8 sig |
|
9 type preprocessor = thm -> Proof.context -> (thm list * Proof.context) |
|
10 |
9 datatype level = Concrete | Generic |
11 datatype level = Concrete | Generic |
10 |
12 |
11 val app_thm_attr : attribute context_parser |
13 val app_thm_attr : attribute context_parser |
12 val dest_thm_attr : attribute context_parser |
14 val dest_thm_attr : attribute context_parser |
|
15 val cong_thm_attr : attribute context_parser |
13 val measurable_thm_attr : bool * (bool * level) -> attribute |
16 val measurable_thm_attr : bool * (bool * level) -> attribute |
14 |
17 |
|
18 val add_del_cong_thm : bool -> thm -> Context.generic -> Context.generic ; |
|
19 |
|
20 val get_all : Context.generic -> thm list |
|
21 val get_dest : Context.generic -> thm list |
|
22 val get_cong : Context.generic -> thm list |
|
23 |
15 val measurable_tac : Proof.context -> thm list -> tactic |
24 val measurable_tac : Proof.context -> thm list -> tactic |
16 |
25 |
17 val simproc : Proof.context -> cterm -> thm option |
26 val simproc : Proof.context -> cterm -> thm option |
18 |
27 |
19 val get_thms : Proof.context -> thm list |
28 val add_preprocessor : string -> preprocessor -> Context.generic -> Context.generic |
20 val get_all : Proof.context -> thm list |
29 val del_preprocessor : string -> Context.generic -> Context.generic |
|
30 val add_local_cong : thm -> Proof.context -> Proof.context |
21 end ; |
31 end ; |
22 |
32 |
23 structure Measurable : MEASURABLE = |
33 structure Measurable : MEASURABLE = |
24 struct |
34 struct |
25 |
35 |
|
36 type preprocessor = thm -> Proof.context -> (thm list * Proof.context) |
|
37 |
26 datatype level = Concrete | Generic; |
38 datatype level = Concrete | Generic; |
27 |
39 |
28 fun eq_measurable_thms ((th1, d1), (th2, d2)) = |
40 fun eq_measurable_thms ((th1, d1), (th2, d2)) = |
29 d1 = d2 andalso Thm.eq_thm_prop (th1, th2) ; |
41 d1 = d2 andalso Thm.eq_thm_prop (th1, th2) ; |
|
42 |
|
43 fun merge_dups (xs:(string * preprocessor) list) ys = |
|
44 xs @ (filter (fn (name, _) => is_none (find_first (fn (name', _) => name' = name) xs)) ys) |
30 |
45 |
31 structure Data = Generic_Data |
46 structure Data = Generic_Data |
32 ( |
47 ( |
33 type T = { |
48 type T = { |
34 measurable_thms : (thm * (bool * level)) Item_Net.T, |
49 measurable_thms : (thm * (bool * level)) Item_Net.T, |
35 dest_thms : thm Item_Net.T, |
50 dest_thms : thm Item_Net.T, |
36 app_thms : thm Item_Net.T } |
51 app_thms : thm Item_Net.T, |
|
52 cong_thms : thm Item_Net.T, |
|
53 preprocessors : (string * preprocessor) list } |
37 val empty = { |
54 val empty = { |
38 measurable_thms = Item_Net.init eq_measurable_thms (single o Thm.prop_of o fst), |
55 measurable_thms = Item_Net.init eq_measurable_thms (single o Thm.prop_of o fst), |
39 dest_thms = Thm.full_rules, |
56 dest_thms = Thm.full_rules, |
40 app_thms = Thm.full_rules }; |
57 app_thms = Thm.full_rules, |
|
58 cong_thms = Thm.full_rules, |
|
59 preprocessors = [] }; |
41 val extend = I; |
60 val extend = I; |
42 fun merge ({measurable_thms = t1, dest_thms = dt1, app_thms = at1 }, |
61 fun merge ({measurable_thms = t1, dest_thms = dt1, app_thms = at1, cong_thms = ct1, preprocessors = i1 }, |
43 {measurable_thms = t2, dest_thms = dt2, app_thms = at2 }) = { |
62 {measurable_thms = t2, dest_thms = dt2, app_thms = at2, cong_thms = ct2, preprocessors = i2 }) = { |
44 measurable_thms = Item_Net.merge (t1, t2), |
63 measurable_thms = Item_Net.merge (t1, t2), |
45 dest_thms = Item_Net.merge (dt1, dt2), |
64 dest_thms = Item_Net.merge (dt1, dt2), |
46 app_thms = Item_Net.merge (at1, at2) }; |
65 app_thms = Item_Net.merge (at1, at2), |
|
66 cong_thms = Item_Net.merge (ct1, ct2), |
|
67 preprocessors = merge_dups i1 i2 |
|
68 }; |
47 ); |
69 ); |
48 |
70 |
49 val debug = |
71 val debug = |
50 Attrib.setup_config_bool @{binding measurable_debug} (K false) |
72 Attrib.setup_config_bool @{binding measurable_debug} (K false) |
51 |
73 |
52 val split = |
74 val split = |
53 Attrib.setup_config_bool @{binding measurable_split} (K true) |
75 Attrib.setup_config_bool @{binding measurable_split} (K true) |
54 |
76 |
55 fun map_data f1 f2 f3 |
77 fun map_data f1 f2 f3 f4 f5 |
56 {measurable_thms = t1, dest_thms = t2, app_thms = t3} = |
78 {measurable_thms = t1, dest_thms = t2, app_thms = t3, cong_thms = t4, preprocessors = t5 } = |
57 {measurable_thms = f1 t1, dest_thms = f2 t2, app_thms = f3 t3 } |
79 {measurable_thms = f1 t1, dest_thms = f2 t2, app_thms = f3 t3, cong_thms = f4 t4, preprocessors = f5 t5} |
58 |
80 |
59 fun map_measurable_thms f = map_data f I I |
81 fun map_measurable_thms f = map_data f I I I I |
60 fun map_dest_thms f = map_data I f I |
82 fun map_dest_thms f = map_data I f I I I |
61 fun map_app_thms f = map_data I I f |
83 fun map_app_thms f = map_data I I f I I |
|
84 fun map_cong_thms f = map_data I I I f I |
|
85 fun map_preprocessors f = map_data I I I I f |
62 |
86 |
63 fun generic_add_del map = |
87 fun generic_add_del map = |
64 Scan.lift |
88 Scan.lift |
65 (Args.add >> K Item_Net.update || Args.del >> K Item_Net.remove || Scan.succeed Item_Net.update) >> |
89 (Args.add >> K Item_Net.update || Args.del >> K Item_Net.remove || Scan.succeed Item_Net.update) >> |
66 (fn f => Thm.declaration_attribute (Data.map o map o f)) |
90 (fn f => Thm.declaration_attribute (Data.map o map o f)) |
67 |
91 |
68 val app_thm_attr = generic_add_del map_app_thms |
92 val app_thm_attr = generic_add_del map_app_thms |
69 |
93 |
70 val dest_thm_attr = generic_add_del map_dest_thms |
94 val dest_thm_attr = generic_add_del map_dest_thms |
71 |
95 |
|
96 val cong_thm_attr = generic_add_del map_cong_thms |
|
97 |
72 fun del_thm th net = |
98 fun del_thm th net = |
73 let |
99 let |
74 val thms = net |> Item_Net.content |> filter (fn (th', _) => Thm.eq_thm (th, th')) |
100 val thms = net |> Item_Net.content |> filter (fn (th', _) => Thm.eq_thm (th, th')) |
75 in fold Item_Net.remove thms net end ; |
101 in fold Item_Net.remove thms net end ; |
76 |
102 |
77 fun measurable_thm_attr (do_add, d) = Thm.declaration_attribute |
103 fun measurable_thm_attr (do_add, d) = Thm.declaration_attribute |
78 (Data.map o map_measurable_thms o (if do_add then Item_Net.update o rpair d else del_thm)) |
104 (Data.map o map_measurable_thms o (if do_add then Item_Net.update o rpair d else del_thm)) |
79 |
105 |
80 val get_dest = Item_Net.content o #dest_thms o Data.get; |
106 val get_dest = Item_Net.content o #dest_thms o Data.get; |
81 val get_app = Item_Net.content o #app_thms o Data.get; |
107 val get_app = Item_Net.content o #app_thms o Data.get; |
|
108 |
|
109 val get_cong = Item_Net.content o #cong_thms o Data.get; |
|
110 val add_cong = Data.map o map_cong_thms o Item_Net.update; |
|
111 val del_cong = Data.map o map_cong_thms o Item_Net.remove; |
|
112 fun add_del_cong_thm true = add_cong |
|
113 | add_del_cong_thm false = del_cong |
|
114 |
|
115 fun add_preprocessor name f = Data.map (map_preprocessors (fn xs => xs @ [(name, f)])) |
|
116 fun del_preprocessor name = Data.map (map_preprocessors (filter (fn (n, _) => n <> name))) |
|
117 val add_local_cong = Context.proof_map o add_cong |
|
118 |
|
119 val get_preprocessors = Context.Proof #> Data.get #> #preprocessors ; |
82 |
120 |
83 fun is_too_generic thm = |
121 fun is_too_generic thm = |
84 let |
122 let |
85 val concl = concl_of thm |
123 val concl = concl_of thm |
86 val concl' = HOLogic.dest_Trueprop concl handle TERM _ => concl |
124 val concl' = HOLogic.dest_Trueprop concl handle TERM _ => concl |
87 in is_Var (head_of concl') end |
125 in is_Var (head_of concl') end |
88 |
126 |
89 fun import_theorem ctxt thm = if is_too_generic thm then [] else |
127 val get_thms = Data.get #> #measurable_thms #> Item_Net.content ; |
90 [thm] @ map_filter (try (fn th' => thm RS th')) (get_dest ctxt); |
128 |
91 |
129 val get_all = get_thms #> map fst ; |
92 val get = Context.Proof #> Data.get #> #measurable_thms #> Item_Net.content ; |
130 |
93 |
131 fun debug_tac ctxt msg f = |
94 val get_all = get #> map fst ; |
132 if Config.get ctxt debug then print_tac ctxt (msg ()) THEN f else f |
95 |
|
96 fun get_thms ctxt = |
|
97 let |
|
98 val thms = ctxt |> get |> rev ; |
|
99 fun get lv = map_filter (fn (th, (rw, lv')) => if lv = lv' then SOME (th, rw) else NONE) thms |
|
100 in |
|
101 get Concrete @ get Generic |> |
|
102 maps (fn (th, rw) => if rw then [th] else import_theorem (Context.Proof ctxt) th) |
|
103 end; |
|
104 |
|
105 fun debug_tac ctxt msg f = if Config.get ctxt debug then print_tac ctxt (msg ()) THEN f else f |
|
106 |
133 |
107 fun nth_hol_goal thm i = |
134 fun nth_hol_goal thm i = |
108 HOLogic.dest_Trueprop (Logic.strip_imp_concl (strip_all_body (nth (prems_of thm) (i - 1)))) |
135 HOLogic.dest_Trueprop (Logic.strip_imp_concl (strip_all_body (nth (prems_of thm) (i - 1)))) |
109 |
136 |
110 fun dest_measurable_fun t = |
137 fun dest_measurable_fun t = |
111 (case t of |
138 (case t of |
112 (Const (@{const_name "Set.member"}, _) $ f $ (Const (@{const_name "measurable"}, _) $ _ $ _)) => f |
139 (Const (@{const_name "Set.member"}, _) $ f $ (Const (@{const_name "measurable"}, _) $ _ $ _)) => f |
113 | _ => raise (TERM ("not a measurability predicate", [t]))) |
140 | _ => raise (TERM ("not a measurability predicate", [t]))) |
114 |
141 |
115 fun is_cond_formula n thm = if length (prems_of thm) < n then false else |
142 fun not_measurable_prop n thm = if length (prems_of thm) < n then false else |
116 (case nth_hol_goal thm n of |
143 (case nth_hol_goal thm n of |
117 (Const (@{const_name "Set.member"}, _) $ _ $ (Const (@{const_name "sets"}, _) $ _)) => false |
144 (Const (@{const_name "Set.member"}, _) $ _ $ (Const (@{const_name "sets"}, _) $ _)) => false |
118 | (Const (@{const_name "Set.member"}, _) $ _ $ (Const (@{const_name "measurable"}, _) $ _ $ _)) => false |
145 | (Const (@{const_name "Set.member"}, _) $ _ $ (Const (@{const_name "measurable"}, _) $ _ $ _)) => false |
119 | _ => true) |
146 | _ => true) |
120 handle TERM _ => true; |
147 handle TERM _ => true; |
146 [SOME T1, SOME T, SOME T2]) |
173 [SOME T1, SOME T, SOME T2]) |
147 end) (cnt_walk t [T]) |
174 end) (cnt_walk t [T]) |
148 end |
175 end |
149 | cnt_prefixes _ _ = [] |
176 | cnt_prefixes _ _ = [] |
150 |
177 |
151 val split_countable_tac = |
|
152 Subgoal.FOCUS (fn {context = ctxt, ...} => SUBGOAL (fn (t, i) => |
|
153 let |
|
154 val f = dest_measurable_fun (HOLogic.dest_Trueprop t) |
|
155 fun cert f = map (Option.map (f (Proof_Context.theory_of ctxt))) |
|
156 fun inst t (ts, Ts) = Drule.instantiate' (cert ctyp_of Ts) (cert cterm_of ts) t |
|
157 val cps = cnt_prefixes ctxt f |> map (inst @{thm measurable_compose_countable}) |
|
158 in if null cps then no_tac else debug_tac ctxt (K "split countable fun") (resolve_tac cps i) end |
|
159 handle TERM _ => no_tac) 1) |
|
160 |
|
161 val split_app_tac = |
|
162 Subgoal.FOCUS (fn {context = ctxt, ...} => SUBGOAL (fn (t, i) => |
|
163 let |
|
164 fun app_prefixes (Abs (n, T, (f $ g))) = let |
|
165 val ps = (if not (loose_bvar1 (g, 0)) then [(f, g)] else []) |
|
166 in map (fn (f, c) => (Abs (n, T, f), c, T, type_of c, type_of1 ([T], f $ c))) ps end |
|
167 | app_prefixes _ = [] |
|
168 |
|
169 fun dest_app (Abs (_, T, t as ((f $ Bound 0) $ c))) = (f, c, T, type_of c, type_of1 ([T], t)) |
|
170 | dest_app t = raise (TERM ("not a measurability predicate of an application", [t])) |
|
171 val thy = Proof_Context.theory_of ctxt |
|
172 val tunify = Sign.typ_unify thy |
|
173 val thms = map |
|
174 (fn thm => (thm, dest_app (dest_measurable_fun (HOLogic.dest_Trueprop (concl_of thm))))) |
|
175 (get_app (Context.Proof ctxt)) |
|
176 fun cert f = map (fn (t, t') => (f thy t, f thy t')) |
|
177 fun inst (f, c, T, Tc, Tf) (thm, (thmf, thmc, thmT, thmTc, thmTf)) = |
|
178 let |
|
179 val inst = |
|
180 (Vartab.empty, ~1) |
|
181 |> tunify (T, thmT) |
|
182 |> tunify (Tf, thmTf) |
|
183 |> tunify (Tc, thmTc) |
|
184 |> Vartab.dest o fst |
|
185 val subst = subst_TVars (map (apsnd snd) inst) |
|
186 in |
|
187 Thm.instantiate (cert ctyp_of (map (fn (n, (s, T)) => (TVar (n, s), T)) inst), |
|
188 cert cterm_of [(subst thmf, f), (subst thmc, c)]) thm |
|
189 end |
|
190 val cps = map_product inst (app_prefixes (dest_measurable_fun (HOLogic.dest_Trueprop t))) thms |
|
191 in if null cps then no_tac |
|
192 else debug_tac ctxt (K ("split app fun")) (resolve_tac cps i) |
|
193 ORELSE debug_tac ctxt (fn () => "FAILED") no_tac end |
|
194 handle TERM t => debug_tac ctxt (fn () => "TERM " ^ fst t ^ Pretty.str_of (Pretty.list "[" "]" (map (Syntax.pretty_term ctxt) (snd t)))) no_tac |
|
195 handle Type.TUNIFY => debug_tac ctxt (fn () => "TUNIFY") no_tac) 1) |
|
196 |
|
197 fun measurable_tac ctxt facts = |
178 fun measurable_tac ctxt facts = |
198 let |
179 let |
199 val imported_thms = |
180 fun debug_fact msg thm () = |
200 (maps (import_theorem (Context.Proof ctxt) o Simplifier.norm_hhf ctxt) facts) @ get_thms ctxt |
181 msg ^ " " ^ Pretty.str_of (Syntax.pretty_term ctxt (prop_of thm)) |
201 |
182 |
202 fun debug_facts msg () = |
183 fun IF' c t i = COND (c i) (t i) no_tac |
203 msg ^ " + " ^ Pretty.str_of (Pretty.list "[" "]" |
184 |
204 (map (Syntax.pretty_term ctxt o prop_of) (maps (import_theorem (Context.Proof ctxt)) facts))); |
185 fun r_tac msg = |
|
186 if Config.get ctxt debug |
|
187 then FIRST' o |
|
188 map (fn thm => resolve_tac [thm] |
|
189 THEN' K (debug_tac ctxt (debug_fact (msg ^ "resolved using") thm) all_tac)) |
|
190 else resolve_tac |
|
191 |
|
192 val elem_congI = @{lemma "A = B \<Longrightarrow> x \<in> B \<Longrightarrow> x \<in> A" by simp} |
|
193 |
|
194 val dests = get_dest (Context.Proof ctxt) |
|
195 fun prep_dest thm = |
|
196 (if is_too_generic thm then [] else [thm] @ map_filter (try (fn th' => thm RS th')) dests) ; |
|
197 val preprocessors = (("std", prep_dest #> pair) :: get_preprocessors ctxt) ; |
|
198 fun preprocess_thm (thm, raw) = |
|
199 if raw then pair [thm] else fold_map (fn (_, proc) => proc thm) preprocessors #>> flat |
|
200 |
|
201 fun sel lv (th, (raw, lv')) = if lv = lv' then SOME (th, raw) else NONE ; |
|
202 fun get lv = ctxt |> Context.Proof |> get_thms |> rev |> map_filter (sel lv) ; |
|
203 val pre_thms = map (Simplifier.norm_hhf ctxt #> rpair false) facts @ get Concrete @ get Generic |
|
204 |
|
205 val (thms, ctxt) = fold_map preprocess_thm pre_thms ctxt |>> flat |
|
206 |
|
207 fun is_sets_eq (Const (@{const_name "HOL.eq"}, _) $ |
|
208 (Const (@{const_name "sets"}, _) $ _) $ |
|
209 (Const (@{const_name "sets"}, _) $ _)) = true |
|
210 | is_sets_eq (Const (@{const_name "HOL.eq"}, _) $ |
|
211 (Const (@{const_name "measurable"}, _) $ _ $ _) $ |
|
212 (Const (@{const_name "measurable"}, _) $ _ $ _)) = true |
|
213 | is_sets_eq _ = false |
|
214 |
|
215 val cong_thms = get_cong (Context.Proof ctxt) @ |
|
216 filter (fn thm => concl_of thm |> HOLogic.dest_Trueprop |> is_sets_eq handle TERM _ => false) facts |
|
217 |
|
218 fun sets_cong_tac i = |
|
219 Subgoal.FOCUS (fn {context = ctxt', prems = prems, ...} => ( |
|
220 let |
|
221 val ctxt'' = Simplifier.add_prems prems ctxt' |
|
222 in |
|
223 r_tac "cong intro" [elem_congI] |
|
224 THEN' SOLVED' (fn i => REPEAT_DETERM ( |
|
225 ((r_tac "cong solve" (cong_thms @ [@{thm refl}]) |
|
226 ORELSE' IF' (fn i => fn thm => nprems_of thm > i) |
|
227 (SOLVED' (asm_full_simp_tac ctxt''))) i))) |
|
228 end) 1) ctxt i |
|
229 THEN flexflex_tac ctxt |
|
230 |
|
231 val simp_solver_tac = |
|
232 IF' not_measurable_prop (debug_tac ctxt (K "simp ") o SOLVED' (asm_full_simp_tac ctxt)) |
|
233 |
|
234 val split_countable_tac = |
|
235 Subgoal.FOCUS (fn {context = ctxt, ...} => SUBGOAL (fn (t, i) => |
|
236 let |
|
237 val f = dest_measurable_fun (HOLogic.dest_Trueprop t) |
|
238 fun cert f = map (Option.map (f (Proof_Context.theory_of ctxt))) |
|
239 fun inst (ts, Ts) = |
|
240 Drule.instantiate' (cert ctyp_of Ts) (cert cterm_of ts) @{thm measurable_compose_countable} |
|
241 in r_tac "split countable" (cnt_prefixes ctxt f |> map inst) i end |
|
242 handle TERM _ => no_tac) 1) |
205 |
243 |
206 val splitter = if Config.get ctxt split then split_countable_tac ctxt else K no_tac |
244 val splitter = if Config.get ctxt split then split_countable_tac ctxt else K no_tac |
207 |
245 |
208 fun REPEAT_cnt f n st = ((f n THEN REPEAT_cnt f (n + 1)) ORELSE all_tac) st |
246 val split_app_tac = |
209 |
247 Subgoal.FOCUS (fn {context = ctxt, ...} => SUBGOAL (fn (t, i) => |
210 val depth_measurable_tac = REPEAT_cnt (fn n => |
248 let |
211 (COND (is_cond_formula 1) |
249 fun app_prefixes (Abs (n, T, (f $ g))) = let |
212 (debug_tac ctxt (K ("simp " ^ string_of_int n)) (SOLVED' (asm_full_simp_tac ctxt) 1)) |
250 val ps = (if not (loose_bvar1 (g, 0)) then [(f, g)] else []) |
213 ((debug_tac ctxt (K ("single " ^ string_of_int n)) (resolve_tac imported_thms 1)) APPEND |
251 in map (fn (f, c) => (Abs (n, T, f), c, T, type_of c, type_of1 ([T], f $ c))) ps end |
214 (split_app_tac ctxt 1) APPEND |
252 | app_prefixes _ = [] |
215 (splitter 1)))) 0 |
253 |
216 |
254 fun dest_app (Abs (_, T, t as ((f $ Bound 0) $ c))) = (f, c, T, type_of c, type_of1 ([T], t)) |
217 in debug_tac ctxt (debug_facts "start") depth_measurable_tac end; |
255 | dest_app t = raise (TERM ("not a measurability predicate of an application", [t])) |
|
256 val thy = Proof_Context.theory_of ctxt |
|
257 val tunify = Sign.typ_unify thy |
|
258 val thms = map |
|
259 (fn thm => (thm, dest_app (dest_measurable_fun (HOLogic.dest_Trueprop (concl_of thm))))) |
|
260 (get_app (Context.Proof ctxt)) |
|
261 fun cert f = map (fn (t, t') => (f thy t, f thy t')) |
|
262 fun inst (f, c, T, Tc, Tf) (thm, (thmf, thmc, thmT, thmTc, thmTf)) = |
|
263 let |
|
264 val inst = |
|
265 (Vartab.empty, ~1) |
|
266 |> tunify (T, thmT) |
|
267 |> tunify (Tf, thmTf) |
|
268 |> tunify (Tc, thmTc) |
|
269 |> Vartab.dest o fst |
|
270 val subst = subst_TVars (map (apsnd snd) inst) |
|
271 in |
|
272 Thm.instantiate (cert ctyp_of (map (fn (n, (s, T)) => (TVar (n, s), T)) inst), |
|
273 cert cterm_of [(subst thmf, f), (subst thmc, c)]) thm |
|
274 end |
|
275 val cps = map_product inst (app_prefixes (dest_measurable_fun (HOLogic.dest_Trueprop t))) thms |
|
276 in if null cps then no_tac |
|
277 else r_tac "split app" cps i ORELSE debug_tac ctxt (fn () => "split app fun FAILED") no_tac end |
|
278 handle TERM t => debug_tac ctxt (fn () => "TERM " ^ fst t ^ Pretty.str_of (Pretty.list "[" "]" (map (Syntax.pretty_term ctxt) (snd t)))) no_tac |
|
279 handle Type.TUNIFY => debug_tac ctxt (fn () => "TUNIFY") no_tac) 1) |
|
280 |
|
281 val single_step_tac = |
|
282 simp_solver_tac |
|
283 ORELSE' r_tac "step" thms |
|
284 ORELSE' (split_app_tac ctxt) |
|
285 ORELSE' splitter |
|
286 ORELSE' (CHANGED o sets_cong_tac) |
|
287 ORELSE' (K (debug_tac ctxt (K "backtrack") no_tac)) |
|
288 |
|
289 in debug_tac ctxt (K "start") (REPEAT (single_step_tac 1)) end; |
218 |
290 |
219 fun simproc ctxt redex = |
291 fun simproc ctxt redex = |
220 let |
292 let |
221 val t = HOLogic.mk_Trueprop (term_of redex); |
293 val t = HOLogic.mk_Trueprop (term_of redex); |
222 fun tac {context = ctxt, prems = _ } = |
294 fun tac {context = ctxt, prems = _ } = |