wenzelm@16978: (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) dixon@15538: (* Title: Provers/eqsubst.ML wenzelm@16434: ID: $Id$ paulson@15481: Author: Lucas Dixon, University of Edinburgh paulson@15481: lucas.dixon@ed.ac.uk wenzelm@16978: Modified: 18 Feb 2005 - Lucas - paulson@15481: Created: 29 Jan 2005 paulson@15481: *) wenzelm@16978: (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) paulson@15481: (* DESCRIPTION: paulson@15481: paulson@15481: A Tactic to perform a substiution using an equation. paulson@15481: paulson@15481: *) paulson@15481: (* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) paulson@15481: dixon@16004: dixon@16004: dixon@15538: (* Logic specific data stub *) paulson@15481: signature EQRULE_DATA = paulson@15481: sig dixon@15538: paulson@15481: (* to make a meta equality theorem in the current logic *) paulson@15481: val prep_meta_eq : thm -> thm list dixon@15538: paulson@15481: end; paulson@15481: dixon@15538: paulson@15481: (* the signature of an instance of the SQSUBST tactic *) wenzelm@16978: signature EQSUBST_TAC = paulson@15481: sig dixon@15538: wenzelm@16978: exception eqsubst_occL_exp of wenzelm@16978: string * (int list) * (thm list) * int * thm; dixon@15959: dixon@16004: wenzelm@16978: type match = wenzelm@16978: ((indexname * (sort * typ)) list (* type instantiations *) wenzelm@16978: * (indexname * (typ * term)) list) (* term instantiations *) wenzelm@16978: * (string * typ) list (* fake named type abs env *) wenzelm@16978: * (string * typ) list (* type abs env *) wenzelm@16978: * term (* outer term *) dixon@15550: wenzelm@16978: type searchinfo = wenzelm@16978: theory (* sign for matching *) dixon@16004: * int (* maxidx *) dixon@16004: * BasicIsaFTerm.FcTerm (* focusterm to search under *) dixon@16004: dixon@15538: val prep_subst_in_asm : dixon@16004: int (* subgoal to subst in *) wenzelm@16978: -> thm (* target theorem with subgoals *) dixon@15538: -> int (* premise to subst in *) wenzelm@16978: -> (cterm list (* certified free var placeholders for vars *) dixon@15538: * int (* premice no. to subst *) dixon@15538: * int (* number of assumptions of premice *) wenzelm@16978: * thm) (* premice as a new theorem for forward reasoning *) dixon@16004: * searchinfo (* search info: prem id etc *) dixon@15538: dixon@15538: val prep_subst_in_asms : dixon@16004: int (* subgoal to subst in *) wenzelm@16978: -> thm (* target theorem with subgoals *) wenzelm@16978: -> ((cterm list (* certified free var placeholders for vars *) dixon@15538: * int (* premice no. to subst *) dixon@15538: * int (* number of assumptions of premice *) wenzelm@16978: * thm) (* premice as a new theorem for forward reasoning *) dixon@16004: * searchinfo) list dixon@15538: dixon@15538: val apply_subst_in_asm : dixon@15538: int (* subgoal *) wenzelm@16978: -> thm (* overall theorem *) wenzelm@16978: -> thm (* rule *) wenzelm@16978: -> (cterm list (* certified free var placeholders for vars *) dixon@15538: * int (* assump no being subst *) wenzelm@16978: * int (* num of premises of asm *) wenzelm@16978: * thm) (* premthm *) dixon@16004: * match wenzelm@16978: -> thm Seq.seq dixon@15538: dixon@15538: val prep_concl_subst : dixon@16004: int (* subgoal *) wenzelm@16978: -> thm (* overall goal theorem *) wenzelm@16978: -> (cterm list * thm) * searchinfo (* (cvfs, conclthm), matchf *) dixon@15538: dixon@15538: val apply_subst_in_concl : dixon@15538: int (* subgoal *) wenzelm@16978: -> thm (* thm with all goals *) wenzelm@16978: -> cterm list (* certified free var placeholders for vars *) wenzelm@16978: * thm (* trivial thm of goal concl *) dixon@15538: (* possible matches/unifiers *) wenzelm@16978: -> thm (* rule *) dixon@15550: -> match wenzelm@16978: -> thm Seq.seq (* substituted goal *) dixon@15538: dixon@16004: (* basic notion of search *) wenzelm@16978: val searchf_tlr_unify_all : wenzelm@16978: (searchinfo wenzelm@16978: -> term (* lhs *) dixon@16004: -> match Seq.seq Seq.seq) wenzelm@16978: val searchf_tlr_unify_valid : wenzelm@16978: (searchinfo wenzelm@16978: -> term (* lhs *) dixon@16004: -> match Seq.seq Seq.seq) dixon@15814: wenzelm@16978: (* specialise search constructor for conclusion skipping occurrences. *) dixon@16004: val skip_first_occs_search : dixon@16004: int -> ('a -> 'b -> 'c Seq.seq Seq.seq) -> 'a -> 'b -> 'c Seq.seq dixon@16004: (* specialised search constructor for assumptions using skips *) dixon@16004: val skip_first_asm_occs_search : dixon@16004: ('a -> 'b -> 'c Seq.seq Seq.seq) -> dixon@16004: 'a -> int -> 'b -> 'c IsaPLib.skipseqT dixon@16004: dixon@16004: (* tactics and methods *) wenzelm@16978: val eqsubst_asm_meth : int list -> thm list -> Proof.method wenzelm@16978: val eqsubst_asm_tac : wenzelm@16978: int list -> thm list -> int -> thm -> thm Seq.seq wenzelm@16978: val eqsubst_asm_tac' : dixon@16004: (* search function with skips *) wenzelm@16978: (searchinfo -> int -> term -> match IsaPLib.skipseqT) dixon@16004: -> int (* skip to *) wenzelm@16978: -> thm (* rule *) dixon@16004: -> int (* subgoal number *) wenzelm@16978: -> thm (* tgt theorem with subgoals *) wenzelm@16978: -> thm Seq.seq (* new theorems *) dixon@15538: wenzelm@16978: val eqsubst_meth : int list -> thm list -> Proof.method wenzelm@16978: val eqsubst_tac : wenzelm@16978: int list -> thm list -> int -> thm -> thm Seq.seq wenzelm@16978: val eqsubst_tac' : wenzelm@16978: (searchinfo -> term -> match Seq.seq) wenzelm@16978: -> thm -> int -> thm -> thm Seq.seq dixon@15538: wenzelm@16978: val meth : (bool * int list) * thm list -> Proof.context -> Proof.method paulson@15481: val setup : (Theory.theory -> Theory.theory) list paulson@15481: end; paulson@15481: dixon@16004: wenzelm@16978: functor EQSubstTacFUN (structure EqRuleData : EQRULE_DATA) dixon@15538: : EQSUBST_TAC paulson@15481: = struct paulson@15481: dixon@15915: (* a type abriviation for match information *) wenzelm@16978: type match = wenzelm@16978: ((indexname * (sort * typ)) list (* type instantiations *) wenzelm@16978: * (indexname * (typ * term)) list) (* term instantiations *) wenzelm@16978: * (string * typ) list (* fake named type abs env *) wenzelm@16978: * (string * typ) list (* type abs env *) wenzelm@16978: * term (* outer term *) dixon@15550: wenzelm@16978: type searchinfo = dixon@16004: Sign.sg (* sign for matching *) dixon@16004: * int (* maxidx *) dixon@16004: * BasicIsaFTerm.FcTerm (* focusterm to search under *) dixon@15550: dixon@15538: (* FOR DEBUGGING... dixon@15538: type trace_subst_errT = int (* subgoal *) wenzelm@16978: * thm (* thm with all goals *) dixon@15538: * (Thm.cterm list (* certified free var placeholders for vars *) wenzelm@16978: * thm) (* trivial thm of goal concl *) dixon@15538: (* possible matches/unifiers *) wenzelm@16978: * thm (* rule *) wenzelm@16978: * (((indexname * typ) list (* type instantiations *) wenzelm@16978: * (indexname * term) list ) (* term instantiations *) wenzelm@16978: * (string * typ) list (* Type abs env *) wenzelm@16978: * term) (* outer term *); dixon@15538: dixon@15538: val trace_subst_err = (ref NONE : trace_subst_errT option ref); dixon@15538: val trace_subst_search = ref false; dixon@15538: exception trace_subst_exp of trace_subst_errT; dixon@15538: *) dixon@15538: wenzelm@16978: (* also defined in /HOL/Tools/inductive_codegen.ML, dixon@15538: maybe move this to seq.ML ? *) dixon@15538: infix 5 :->; dixon@15538: fun s :-> f = Seq.flat (Seq.map f s); dixon@15538: dixon@15814: (* search from top, left to right, then down *) wenzelm@16978: fun search_tlr_all_f f ft = paulson@15481: let wenzelm@16978: fun maux ft = wenzelm@16978: let val t' = (IsaFTerm.focus_of_fcterm ft) wenzelm@16978: (* val _ = wenzelm@16978: if !trace_subst_search then dixon@15538: (writeln ("Examining: " ^ (TermLib.string_of_term t')); dixon@15538: TermLib.writeterm t'; ()) dixon@15538: else (); *) wenzelm@16978: in wenzelm@16978: (case t' of wenzelm@16978: (_ $ _) => Seq.append(maux (IsaFTerm.focus_left ft), wenzelm@16978: Seq.cons(f ft, paulson@15481: maux (IsaFTerm.focus_right ft))) dixon@15929: | (Abs _) => Seq.cons(f ft, maux (IsaFTerm.focus_abs ft)) dixon@15929: | leaf => Seq.single (f ft)) end paulson@15481: in maux ft end; paulson@15481: dixon@15814: (* search from top, left to right, then down *) wenzelm@16978: fun search_tlr_valid_f f ft = dixon@15814: let wenzelm@16978: fun maux ft = wenzelm@16978: let dixon@15814: val hereseq = if IsaFTerm.valid_match_start ft then f ft else Seq.empty wenzelm@16978: in wenzelm@16978: (case (IsaFTerm.focus_of_fcterm ft) of wenzelm@16978: (_ $ _) => Seq.append(maux (IsaFTerm.focus_left ft), wenzelm@16978: Seq.cons(hereseq, dixon@15814: maux (IsaFTerm.focus_right ft))) dixon@15929: | (Abs _) => Seq.cons(hereseq, maux (IsaFTerm.focus_abs ft)) dixon@15929: | leaf => Seq.single (hereseq)) dixon@15814: end dixon@15814: in maux ft end; dixon@15814: dixon@15814: (* search all unifications *) wenzelm@16978: fun searchf_tlr_unify_all (sgn, maxidx, ft) lhs = wenzelm@16978: IsaFTerm.find_fcterm_matches wenzelm@16978: search_tlr_all_f dixon@16004: (IsaFTerm.clean_unify_ft sgn maxidx lhs) dixon@16004: ft; paulson@15481: dixon@15814: (* search only for 'valid' unifiers (non abs subterms and non vars) *) wenzelm@16978: fun searchf_tlr_unify_valid (sgn, maxidx, ft) lhs = wenzelm@16978: IsaFTerm.find_fcterm_matches wenzelm@16978: search_tlr_valid_f dixon@16004: (IsaFTerm.clean_unify_ft sgn maxidx lhs) dixon@16004: ft; dixon@15929: dixon@15814: dixon@15538: (* apply a substitution in the conclusion of the theorem th *) dixon@15538: (* cfvs are certified free var placeholders for goal params *) dixon@15538: (* conclthm is a theorem of for just the conclusion *) dixon@15538: (* m is instantiation/match information *) dixon@15538: (* rule is the equation for substitution *) wenzelm@16978: fun apply_subst_in_concl i th (cfvs, conclthm) rule m = dixon@15538: (RWInst.rw m rule conclthm) dixon@15855: |> IsaND.unfix_frees cfvs dixon@15915: |> RWInst.beta_eta_contract dixon@15538: |> (fn r => Tactic.rtac r i th); paulson@15481: paulson@15481: (* substitute within the conclusion of goal i of gth, using a meta dixon@15538: equation rule. Note that we assume rule has var indicies zero'd *) wenzelm@16978: fun prep_concl_subst i gth = wenzelm@16978: let paulson@15481: val th = Thm.incr_indexes 1 gth; paulson@15481: val tgt_term = Thm.prop_of th; paulson@15481: paulson@15481: val sgn = Thm.sign_of_thm th; paulson@15481: val ctermify = Thm.cterm_of sgn; paulson@15481: val trivify = Thm.trivial o ctermify; paulson@15481: paulson@15481: val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term; paulson@15481: val cfvs = rev (map ctermify fvs); paulson@15481: dixon@15538: val conclterm = Logic.strip_imp_concl fixedbody; dixon@15538: val conclthm = trivify conclterm; dixon@15538: val maxidx = Term.maxidx_of_term conclterm; wenzelm@16978: val ft = ((IsaFTerm.focus_right dixon@16004: o IsaFTerm.focus_left wenzelm@16978: o IsaFTerm.fcterm_of_term dixon@16004: o Thm.prop_of) conclthm) paulson@15481: in dixon@16004: ((cfvs, conclthm), (sgn, maxidx, ft)) paulson@15481: end; paulson@15481: paulson@15481: (* substitute using an object or meta level equality *) wenzelm@16978: fun eqsubst_tac' searchf instepthm i th = wenzelm@16978: let dixon@16004: val (cvfsconclthm, searchinfo) = prep_concl_subst i th; wenzelm@16978: val stepthms = wenzelm@16978: Seq.map Drule.zero_var_indexes dixon@15538: (Seq.of_list (EqRuleData.prep_meta_eq instepthm)); dixon@15538: fun rewrite_with_thm r = dixon@15538: let val (lhs,_) = Logic.dest_equals (Thm.concl_of r); dixon@16004: in (searchf searchinfo lhs) dixon@15538: :-> (apply_subst_in_concl i th cvfsconclthm r) end; dixon@16004: in stepthms :-> rewrite_with_thm end; dixon@15538: dixon@15538: dixon@16004: (* Tactic.distinct_subgoals_tac -- fails to free type variables *) dixon@15959: wenzelm@16978: (* custom version of distinct subgoals that works with term and wenzelm@16978: type variables. Asssumes th is in beta-eta normal form. dixon@15959: Also, does nothing if flexflex contraints are present. *) dixon@15959: fun distinct_subgoals th = dixon@15959: if List.null (Thm.tpairs_of th) then dixon@15959: let val (fixes,fixedthm) = IsaND.fix_vars_and_tvars th dixon@15959: val (fixedthconcl,cprems) = IsaND.hide_prems fixedthm dixon@15959: in wenzelm@16978: IsaND.unfix_frees_and_tfrees dixon@15959: fixes wenzelm@16978: (Drule.implies_intr_list wenzelm@16978: (Library.gen_distinct dixon@15959: (fn (x, y) => Thm.term_of x = Thm.term_of y) dixon@15959: cprems) fixedthconcl) dixon@15959: end dixon@15959: else th; dixon@15538: wenzelm@16978: (* General substiuttion of multiple occurances using one of dixon@15936: the given theorems*) wenzelm@16978: exception eqsubst_occL_exp of wenzelm@16978: string * (int list) * (thm list) * int * thm; wenzelm@16978: fun skip_first_occs_search occ srchf sinfo lhs = wenzelm@16978: case (IsaPLib.skipto_seqseq occ (srchf sinfo lhs)) of dixon@16004: IsaPLib.skipmore _ => Seq.empty dixon@16004: | IsaPLib.skipseq ss => Seq.flat ss; dixon@16004: wenzelm@16978: fun eqsubst_tac occL thms i th = dixon@15936: let val nprems = Thm.nprems_of th in dixon@15936: if nprems < i then Seq.empty else wenzelm@16978: let val thmseq = (Seq.of_list thms) wenzelm@16978: fun apply_occ occ th = wenzelm@16978: thmseq :-> wenzelm@16978: (fn r => eqsubst_tac' (skip_first_occs_search dixon@15936: occ searchf_tlr_unify_valid) r dixon@15936: (i + ((Thm.nprems_of th) - nprems)) dixon@15936: th); wenzelm@16978: val sortedoccL = dixon@16004: Library.sort (Library.rev_order o Library.int_ord) occL; dixon@15936: in dixon@16004: Seq.map distinct_subgoals (Seq.EVERY (map apply_occ sortedoccL) th) dixon@15936: end dixon@15959: end dixon@15959: handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th); dixon@15959: paulson@15481: paulson@15481: (* inthms are the given arguments in Isar, and treated as eqstep with paulson@15481: the first one, then the second etc *) dixon@15936: fun eqsubst_meth occL inthms = wenzelm@16978: Method.METHOD dixon@15538: (fn facts => dixon@15936: HEADGOAL ( Method.insert_tac facts THEN' eqsubst_tac occL inthms )); paulson@15481: dixon@16004: (* apply a substitution inside assumption j, keeps asm in the same place *) wenzelm@16978: fun apply_subst_in_asm i th rule ((cfvs, j, ngoalprems, pth),m) = wenzelm@16978: let dixon@16004: val th2 = Thm.rotate_rule (j - 1) i th; (* put premice first *) wenzelm@16978: val preelimrule = dixon@16004: (RWInst.rw m rule pth) dixon@16004: |> (Seq.hd o Tactic.prune_params_tac) dixon@16004: |> Thm.permute_prems 0 ~1 (* put old asm first *) dixon@16004: |> IsaND.unfix_frees cfvs (* unfix any global params *) dixon@16004: |> RWInst.beta_eta_contract; (* normal form *) wenzelm@16978: (* val elimrule = dixon@16004: preelimrule dixon@16004: |> Tactic.make_elim (* make into elim rule *) dixon@16004: |> Thm.lift_rule (th2, i); (* lift into context *) dixon@16007: *) dixon@16004: in dixon@16004: (* ~j because new asm starts at back, thus we subtract 1 *) dixon@16007: Seq.map (Thm.rotate_rule (~j) ((Thm.nprems_of rule) + i)) dixon@16007: (Tactic.dtac preelimrule i th2) dixon@16007: wenzelm@16978: (* (Thm.bicompose dixon@16004: false (* use unification *) dixon@16004: (true, (* elim resolution *) dixon@16007: elimrule, (2 + (Thm.nprems_of rule)) - ngoalprems) dixon@16007: i th2) *) dixon@16004: end; paulson@15481: paulson@15481: dixon@15538: (* prepare to substitute within the j'th premise of subgoal i of gth, dixon@15538: using a meta-level equation. Note that we assume rule has var indicies dixon@15538: zero'd. Note that we also assume that premt is the j'th premice of dixon@15538: subgoal i of gth. Note the repetition of work done for each dixon@15538: assumption, i.e. this can be made more efficient for search over dixon@15538: multiple assumptions. *) wenzelm@16978: fun prep_subst_in_asm i gth j = wenzelm@16978: let paulson@15481: val th = Thm.incr_indexes 1 gth; paulson@15481: val tgt_term = Thm.prop_of th; paulson@15481: paulson@15481: val sgn = Thm.sign_of_thm th; paulson@15481: val ctermify = Thm.cterm_of sgn; paulson@15481: val trivify = Thm.trivial o ctermify; paulson@15481: paulson@15481: val (fixedbody, fvs) = IsaND.fix_alls_term i tgt_term; paulson@15481: val cfvs = rev (map ctermify fvs); paulson@15481: dixon@15538: val asmt = Library.nth_elem(j - 1,(Logic.strip_imp_prems fixedbody)); dixon@15538: val asm_nprems = length (Logic.strip_imp_prems asmt); dixon@15538: dixon@15538: val pth = trivify asmt; dixon@15538: val maxidx = Term.maxidx_of_term asmt; dixon@15538: wenzelm@16978: val ft = ((IsaFTerm.focus_right wenzelm@16978: o IsaFTerm.fcterm_of_term dixon@16004: o Thm.prop_of) pth) dixon@16004: in ((cfvs, j, asm_nprems, pth), (sgn, maxidx, ft)) end; paulson@15481: dixon@15538: (* prepare subst in every possible assumption *) wenzelm@16978: fun prep_subst_in_asms i gth = dixon@16004: map (prep_subst_in_asm i gth) wenzelm@16978: ((rev o IsaPLib.mk_num_list o length) dixon@16004: (Logic.prems_of_goal (Thm.prop_of gth) i)); dixon@15538: dixon@15538: dixon@15538: (* substitute in an assumption using an object or meta level equality *) wenzelm@16978: fun eqsubst_asm_tac' searchf skipocc instepthm i th = wenzelm@16978: let dixon@16004: val asmpreps = prep_subst_in_asms i th; wenzelm@16978: val stepthms = wenzelm@16978: Seq.map Drule.zero_var_indexes dixon@16004: (Seq.of_list (EqRuleData.prep_meta_eq instepthm)) dixon@16004: fun rewrite_with_thm r = dixon@16004: let val (lhs,_) = Logic.dest_equals (Thm.concl_of r) dixon@16004: fun occ_search occ [] = Seq.empty dixon@16004: | occ_search occ ((asminfo, searchinfo)::moreasms) = wenzelm@16978: (case searchf searchinfo occ lhs of dixon@16004: IsaPLib.skipmore i => occ_search i moreasms wenzelm@16978: | IsaPLib.skipseq ss => dixon@16004: Seq.append (Seq.map (Library.pair asminfo) wenzelm@16978: (Seq.flat ss), dixon@16004: occ_search 1 moreasms)) dixon@16004: (* find later substs also *) wenzelm@16978: in dixon@16004: (occ_search skipocc asmpreps) :-> (apply_subst_in_asm i th r) dixon@16004: end; dixon@16004: in stepthms :-> rewrite_with_thm end; dixon@15538: dixon@16004: wenzelm@16978: fun skip_first_asm_occs_search searchf sinfo occ lhs = dixon@16004: IsaPLib.skipto_seqseq occ (searchf sinfo lhs); dixon@16004: wenzelm@16978: fun eqsubst_asm_tac occL thms i th = wenzelm@16978: let val nprems = Thm.nprems_of th dixon@15538: in dixon@16004: if nprems < i then Seq.empty else wenzelm@16978: let val thmseq = (Seq.of_list thms) wenzelm@16978: fun apply_occ occK th = wenzelm@16978: thmseq :-> wenzelm@16978: (fn r => wenzelm@16978: eqsubst_asm_tac' (skip_first_asm_occs_search dixon@16004: searchf_tlr_unify_valid) occK r dixon@16004: (i + ((Thm.nprems_of th) - nprems)) dixon@16004: th); wenzelm@16978: val sortedoccs = dixon@16004: Library.sort (Library.rev_order o Library.int_ord) occL dixon@16004: in dixon@16004: Seq.map distinct_subgoals dixon@16004: (Seq.EVERY (map apply_occ sortedoccs) th) dixon@16004: end dixon@16004: end dixon@16004: handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th); paulson@15481: paulson@15481: (* inthms are the given arguments in Isar, and treated as eqstep with paulson@15481: the first one, then the second etc *) dixon@15936: fun eqsubst_asm_meth occL inthms = wenzelm@16978: Method.METHOD dixon@15538: (fn facts => dixon@15936: HEADGOAL (Method.insert_tac facts THEN' eqsubst_asm_tac occL inthms )); paulson@15481: paulson@15481: (* combination method that takes a flag (true indicates that subst paulson@15481: should be done to an assumption, false = apply to the conclusion of paulson@15481: the goal) as well as the theorems to use *) wenzelm@16978: fun meth ((asmflag, occL), inthms) ctxt = dixon@15936: if asmflag then eqsubst_asm_meth occL inthms else eqsubst_meth occL inthms; paulson@15481: paulson@15481: (* syntax for options, given "(asm)" will give back true, without paulson@15481: gives back false *) paulson@15481: val options_syntax = paulson@15481: (Args.parens (Args.$$$ "asm") >> (K true)) || paulson@15481: (Scan.succeed false); dixon@15936: dixon@15929: val ith_syntax = dixon@15936: (Args.parens (Scan.repeat Args.nat)) dixon@15936: || (Scan.succeed [0]); paulson@15481: paulson@15481: (* method syntax, first take options, then theorems *) paulson@15481: fun meth_syntax meth src ctxt = wenzelm@16978: meth (snd (Method.syntax ((Scan.lift options_syntax) wenzelm@16978: -- (Scan.lift ith_syntax) wenzelm@16978: -- Attrib.local_thms) src ctxt)) paulson@15481: ctxt; paulson@15481: paulson@15481: (* setup function for adding method to theory. *) wenzelm@16978: val setup = paulson@15481: [Method.add_method ("subst", meth_syntax meth, "Substiution with an equation. Use \"(asm)\" option to substitute in an assumption.")]; paulson@15481: wenzelm@16978: end;