wenzelm@5824: (* Title: Pure/Isar/method.ML wenzelm@5824: ID: $Id$ wenzelm@5824: Author: Markus Wenzel, TU Muenchen wenzelm@5824: wenzelm@5824: Proof methods. wenzelm@5824: *) wenzelm@5824: wenzelm@5824: signature BASIC_METHOD = wenzelm@5824: sig wenzelm@5824: val print_methods: theory -> unit wenzelm@5824: val Method: bstring -> (Args.src -> Proof.context -> Proof.method) -> string -> unit wenzelm@5824: end; wenzelm@5824: wenzelm@5824: signature METHOD = wenzelm@5824: sig wenzelm@5824: include BASIC_METHOD wenzelm@5824: val LIFT: tactic -> thm -> (thm * (indexname * term) list * (string * tthm list) list) Seq.seq wenzelm@5824: val METHOD: (tthm list -> tactic) -> Proof.method wenzelm@5824: val METHOD0: tactic -> Proof.method wenzelm@5824: val fail: Proof.method wenzelm@5824: val succeed: Proof.method wenzelm@5824: val trivial: Proof.method wenzelm@5824: val assumption: Proof.method wenzelm@5824: val forward_chain: thm list -> thm list -> thm Seq.seq wenzelm@5824: val rule_tac: tthm list -> tthm list -> int -> tactic wenzelm@5824: val rule: tthm list -> Proof.method wenzelm@5824: val method: theory -> Args.src -> Proof.context -> Proof.method wenzelm@5824: val add_methods: (bstring * (Args.src -> Proof.context -> Proof.method) * string) list wenzelm@5824: -> theory -> theory wenzelm@5824: datatype text = wenzelm@5824: Basic of (Proof.context -> Proof.method) | wenzelm@5824: Source of Args.src | wenzelm@5824: Then of text list | wenzelm@5824: Orelse of text list | wenzelm@5824: Try of text | wenzelm@5824: Repeat of text | wenzelm@5824: Repeat1 of text wenzelm@5824: val dynamic_method: string -> (Proof.context -> Proof.method) wenzelm@5824: val refine: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val tac: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val etac: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val proof: text option -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val end_block: Proof.state -> Proof.state Seq.seq wenzelm@5824: val terminal_proof: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val trivial_proof: Proof.state -> Proof.state Seq.seq wenzelm@5824: val default_proof: Proof.state -> Proof.state Seq.seq wenzelm@5824: val qed: bstring option -> theory attribute list option -> Proof.state wenzelm@5824: -> theory * (string * string * tthm) wenzelm@5824: val syntax: (Args.T list -> 'a * Args.T list) -> ('a -> 'b) -> Args.src -> 'b wenzelm@5824: val no_args: 'a -> Args.src -> Proof.context -> 'a wenzelm@5824: val thm_args: (tthm list -> 'a) -> Args.src -> Proof.context -> 'a wenzelm@5824: val sectioned_args: (Proof.context -> 'a) -> ('a * tthm list -> 'b) -> wenzelm@5824: (string * ('b * tthm list -> 'b)) list -> ('b -> 'c) -> Args.src -> Proof.context -> 'c wenzelm@5824: val setup: (theory -> theory) list wenzelm@5824: end; wenzelm@5824: wenzelm@5824: structure Method: METHOD = wenzelm@5824: struct wenzelm@5824: wenzelm@5824: wenzelm@5824: (** proof methods **) wenzelm@5824: wenzelm@5824: (* method from tactic *) wenzelm@5824: wenzelm@5824: fun LIFT tac goal = Seq.map (fn x => (x, [], [])) (tac goal); wenzelm@5824: fun METHOD tacf = Proof.method (LIFT o tacf); wenzelm@5824: fun METHOD0 tac = METHOD (fn [] => tac | _ => error "Method may not be used with facts"); wenzelm@5824: wenzelm@5824: wenzelm@5824: (* primitive *) wenzelm@5824: wenzelm@5824: val fail = METHOD (K no_tac); wenzelm@5824: val succeed = METHOD (K all_tac); wenzelm@5824: wenzelm@5824: wenzelm@5824: (* trivial, assumption *) wenzelm@5824: wenzelm@5824: fun trivial_tac [] = K all_tac wenzelm@5824: | trivial_tac facts = wenzelm@5824: let wenzelm@5824: val thms = map Attribute.thm_of facts; wenzelm@5824: val r = ~ (length facts); wenzelm@5824: in metacuts_tac thms THEN' rotate_tac r end; wenzelm@5824: wenzelm@5824: val trivial = METHOD (ALLGOALS o trivial_tac); wenzelm@5824: val assumption = METHOD (fn facts => FIRSTGOAL (trivial_tac facts THEN' assume_tac)); wenzelm@5824: wenzelm@5824: val asm_finish = METHOD (K (TRYALL assume_tac)); wenzelm@5824: wenzelm@5824: wenzelm@5824: (* rule *) wenzelm@5824: wenzelm@5824: fun res th i rule = Thm.biresolution false [(false, th)] i rule handle THM _ => Seq.empty; wenzelm@5824: wenzelm@5824: fun multi_resolve facts rule = wenzelm@5824: let wenzelm@5824: fun multi_res i [] = Seq.single rule wenzelm@5824: | multi_res i (th :: ths) = Seq.flat (Seq.map (res th i) (multi_res (i + 1) ths)) wenzelm@5824: in multi_res 1 facts end; wenzelm@5824: wenzelm@5824: fun forward_chain facts rules = Seq.flat (Seq.map (multi_resolve facts) (Seq.of_list rules)); wenzelm@5824: wenzelm@5824: fun rule_tac rules [] = resolve_tac (map Attribute.thm_of rules) wenzelm@5824: | rule_tac erules facts = wenzelm@5824: let wenzelm@5824: val rules = forward_chain (map Attribute.thm_of facts) (map Attribute.thm_of erules); wenzelm@5824: fun tac i state = Seq.flat (Seq.map (fn rule => Tactic.rtac rule i state) rules); wenzelm@5824: in tac end; wenzelm@5824: wenzelm@5824: fun rule rules = METHOD (FIRSTGOAL o rule_tac rules); wenzelm@5824: wenzelm@5824: wenzelm@5824: wenzelm@5824: (** methods theory data **) wenzelm@5824: wenzelm@5824: (* data kind 'Isar/methods' *) wenzelm@5824: wenzelm@5824: structure MethodsDataArgs = wenzelm@5824: struct wenzelm@5824: val name = "Isar/methods"; wenzelm@5824: type T = wenzelm@5824: {space: NameSpace.T, wenzelm@5824: meths: (((Args.src -> Proof.context -> Proof.method) * string) * stamp) Symtab.table}; wenzelm@5824: wenzelm@5824: val empty = {space = NameSpace.empty, meths = Symtab.empty}; wenzelm@5824: val prep_ext = I; wenzelm@5824: fun merge ({space = space1, meths = meths1}, {space = space2, meths = meths2}) = wenzelm@5824: {space = NameSpace.merge (space1, space2), wenzelm@5824: meths = Symtab.merge eq_snd (meths1, meths2) handle Symtab.DUPS dups => wenzelm@5824: error ("Attempt to merge different versions of methods " ^ commas_quote dups)}; wenzelm@5824: wenzelm@5824: fun print _ {space, meths} = wenzelm@5824: let wenzelm@5824: fun prt_meth (name, ((_, comment), _)) = Pretty.block wenzelm@5824: [Pretty.str (NameSpace.cond_extern space name ^ ":"), Pretty.brk 2, Pretty.str comment]; wenzelm@5824: in wenzelm@5824: Pretty.writeln (Display.pretty_name_space ("method name space", space)); wenzelm@5824: Pretty.writeln (Pretty.big_list "methods:" (map prt_meth (Symtab.dest meths))) wenzelm@5824: end; wenzelm@5824: end; wenzelm@5824: wenzelm@5824: structure MethodsData = TheoryDataFun(MethodsDataArgs); wenzelm@5824: val print_methods = MethodsData.print; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* get methods *) wenzelm@5824: wenzelm@5824: fun method thy = wenzelm@5824: let wenzelm@5824: val {space, meths} = MethodsData.get thy; wenzelm@5824: wenzelm@5824: fun meth ((raw_name, args), pos) = wenzelm@5824: let val name = NameSpace.intern space raw_name in wenzelm@5824: (case Symtab.lookup (meths, name) of wenzelm@5824: None => error ("Unknown proof method: " ^ quote name ^ Position.str_of pos) wenzelm@5824: | Some ((mth, _), _) => mth ((name, args), pos)) wenzelm@5824: end; wenzelm@5824: in meth end; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* add_methods *) wenzelm@5824: wenzelm@5824: fun add_methods raw_meths thy = wenzelm@5824: let wenzelm@5824: val full = Sign.full_name (Theory.sign_of thy); wenzelm@5824: val new_meths = wenzelm@5824: map (fn (name, f, comment) => (full name, ((f, comment), stamp ()))) raw_meths; wenzelm@5824: wenzelm@5824: val {space, meths} = MethodsData.get thy; wenzelm@5824: val space' = NameSpace.extend (space, map fst new_meths); wenzelm@5824: val meths' = Symtab.extend (meths, new_meths) handle Symtab.DUPS dups => wenzelm@5824: error ("Duplicate declaration of method(s) " ^ commas_quote dups); wenzelm@5824: in wenzelm@5824: thy |> MethodsData.put {space = space', meths = meths'} wenzelm@5824: end; wenzelm@5824: wenzelm@5824: (*implicit version*) wenzelm@5824: fun Method name meth cmt = Context.>> (add_methods [(name, meth, cmt)]); wenzelm@5824: wenzelm@5824: wenzelm@5824: (* argument syntax *) wenzelm@5824: wenzelm@5824: val methodN = "method"; wenzelm@5824: fun syntax scan = Args.syntax methodN scan; wenzelm@5824: wenzelm@5824: fun no_args x = syntax (Scan.succeed (fn (_: Proof.context) => x)) I; wenzelm@5824: wenzelm@5824: (* FIXME move? *) wenzelm@5824: fun thm_args f = syntax (Scan.repeat Args.name) wenzelm@5824: (fn names => fn ctxt => f (ProofContext.get_tthmss ctxt names)); wenzelm@5824: wenzelm@5824: fun sectioned_args get_data def_sect sects f = wenzelm@5824: syntax (Args.sectioned (map fst sects)) wenzelm@5824: (fn (names, sect_names) => fn ctxt => wenzelm@5824: let wenzelm@5824: val get_thms = ProofContext.get_tthmss ctxt; wenzelm@5824: val thms = get_thms names; wenzelm@5824: val sect_thms = map (apsnd get_thms) sect_names; wenzelm@5824: wenzelm@5824: fun apply_sect (data, (s, ths)) = wenzelm@5824: (case assoc (sects, s) of wenzelm@5824: Some add => add (data, ths) wenzelm@5824: | None => error ("Unknown argument section " ^ quote s)); wenzelm@5824: in f (foldl apply_sect (def_sect (get_data ctxt, thms), sect_thms)) end); wenzelm@5824: wenzelm@5824: wenzelm@5824: wenzelm@5824: (** method text **) wenzelm@5824: wenzelm@5824: (* datatype text *) wenzelm@5824: wenzelm@5824: datatype text = wenzelm@5824: Basic of (Proof.context -> Proof.method) | wenzelm@5824: Source of Args.src | wenzelm@5824: Then of text list | wenzelm@5824: Orelse of text list | wenzelm@5824: Try of text | wenzelm@5824: Repeat of text | wenzelm@5824: Repeat1 of text; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* dynamic methods *) wenzelm@5824: wenzelm@5824: fun dynamic_method name = (fn ctxt => wenzelm@5824: method (ProofContext.theory_of ctxt) ((name, []), Position.none) ctxt); wenzelm@5824: wenzelm@5824: wenzelm@5824: (* refine *) wenzelm@5824: wenzelm@5824: fun refine text state = wenzelm@5824: let wenzelm@5824: val thy = Proof.theory_of state; wenzelm@5824: wenzelm@5824: fun eval (Basic mth) = Proof.refine mth wenzelm@5824: | eval (Source src) = Proof.refine (method thy src) wenzelm@5824: | eval (Then txts) = Seq.EVERY (map eval txts) wenzelm@5824: | eval (Orelse txts) = Seq.FIRST (map eval txts) wenzelm@5824: | eval (Try txt) = Seq.TRY (eval txt) wenzelm@5824: | eval (Repeat txt) = Seq.REPEAT (eval txt) wenzelm@5824: | eval (Repeat1 txt) = Seq.REPEAT1 (eval txt); wenzelm@5824: in eval text state end; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* unstructured steps *) wenzelm@5824: wenzelm@5824: fun tac text state = wenzelm@5824: state wenzelm@5824: |> Proof.goal_facts (K []) wenzelm@5824: |> refine text; wenzelm@5824: wenzelm@5824: fun etac text state = wenzelm@5824: state wenzelm@5824: |> Proof.goal_facts Proof.the_facts wenzelm@5824: |> refine text; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* proof steps *) wenzelm@5824: wenzelm@5824: val default_txt = Source (("default", []), Position.none); wenzelm@5824: val finishN = "finish"; wenzelm@5824: wenzelm@5824: fun proof opt_text state = wenzelm@5824: state wenzelm@5824: |> Proof.assert_backward wenzelm@5824: |> refine (if_none opt_text default_txt) wenzelm@5824: |> Seq.map Proof.enter_forward; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* conclusions *) wenzelm@5824: wenzelm@5824: val end_block = Proof.end_block (dynamic_method finishN); wenzelm@5824: wenzelm@5824: fun terminal_proof text = Seq.THEN (proof (Some text), end_block); wenzelm@5824: val trivial_proof = terminal_proof (Basic (K trivial)); wenzelm@5824: val default_proof = terminal_proof default_txt; wenzelm@5824: wenzelm@5824: val qed = Proof.qed (dynamic_method finishN); wenzelm@5824: wenzelm@5824: wenzelm@5824: wenzelm@5824: (** theory setup **) wenzelm@5824: wenzelm@5824: (* pure_methods *) wenzelm@5824: wenzelm@5824: val pure_methods = wenzelm@5824: [("fail", no_args fail, "force failure"), wenzelm@5824: ("succeed", no_args succeed, "succeed"), wenzelm@5824: ("trivial", no_args trivial, "proof all goals trivially"), wenzelm@5824: ("assumption", no_args assumption, "proof by assumption"), wenzelm@5824: ("finish", no_args asm_finish, "finish proof by assumption"), wenzelm@5824: ("rule", thm_args rule, "apply primitive rule")]; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* setup *) wenzelm@5824: wenzelm@5824: val setup = [MethodsData.init, add_methods pure_methods]; wenzelm@5824: wenzelm@5824: wenzelm@5824: end; wenzelm@5824: wenzelm@5824: wenzelm@5824: structure BasicMethod: BASIC_METHOD = Method; wenzelm@5824: open BasicMethod;