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@6091: val METHOD: (thm list -> tactic) -> Proof.method wenzelm@5824: val METHOD0: tactic -> Proof.method wenzelm@5824: val fail: Proof.method wenzelm@5824: val succeed: Proof.method wenzelm@7419: val insert_tac: thm list -> int -> tactic wenzelm@7419: val insert: Proof.method wenzelm@7419: val fold: thm list -> Proof.method wenzelm@7419: val unfold: thm list -> Proof.method wenzelm@7419: val multi_resolve: thm list -> thm -> thm Seq.seq wenzelm@7419: val multi_resolves: thm list -> thm list -> thm Seq.seq wenzelm@6091: val rule_tac: thm list -> thm list -> int -> tactic wenzelm@7130: val erule_tac: thm list -> thm list -> int -> tactic wenzelm@6091: val rule: thm list -> Proof.method wenzelm@7130: val erule: thm list -> Proof.method wenzelm@7419: val assumption: Proof.method wenzelm@7419: val FINISHED: tactic -> tactic wenzelm@7419: val finish: Proof.method wenzelm@5916: exception METHOD_FAIL of (string * Position.T) * exn wenzelm@7419: val help_methods: theory -> unit 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@5884: val syntax: (Proof.context * Args.T list -> 'a * (Proof.context * Args.T list)) -> wenzelm@5884: Proof.context -> Args.src -> Proof.context * 'a wenzelm@5884: val no_args: Proof.method -> Args.src -> Proof.context -> Proof.method wenzelm@7268: type modifier wenzelm@7268: val sectioned_args: ((Args.T list -> modifier * Args.T list) list -> wenzelm@5884: Proof.context * Args.T list -> 'a * (Proof.context * Args.T list)) -> wenzelm@7268: (Args.T list -> modifier * Args.T list) list -> wenzelm@5884: ('a -> Proof.context -> Proof.method) -> Args.src -> Proof.context -> Proof.method wenzelm@7268: val default_sectioned_args: modifier -> wenzelm@7268: (Args.T list -> modifier * Args.T list) list -> wenzelm@5884: (Proof.context -> Proof.method) -> Args.src -> Proof.context -> Proof.method wenzelm@7268: val only_sectioned_args: (Args.T list -> modifier * Args.T list) list -> wenzelm@5884: (Proof.context -> Proof.method) -> Args.src -> Proof.context -> Proof.method wenzelm@6091: val thms_args: (thm list -> Proof.method) -> Args.src -> Proof.context -> Proof.method 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: Repeat1 of text wenzelm@5824: val refine: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val tac: text -> Proof.state -> Proof.state Seq.seq wenzelm@5884: val then_tac: text -> Proof.state -> Proof.state Seq.seq wenzelm@5824: val proof: text option -> Proof.state -> Proof.state Seq.seq wenzelm@6981: val local_qed: text option wenzelm@6981: -> ({kind: string, name: string, thm: thm} -> unit) * (thm -> unit) wenzelm@6736: -> Proof.state -> Proof.state Seq.seq wenzelm@6981: val local_terminal_proof: text * text option wenzelm@6981: -> ({kind: string, name: string, thm: thm} -> unit) * (thm -> unit) wenzelm@6736: -> Proof.state -> Proof.state Seq.seq wenzelm@6981: val local_immediate_proof: ({kind: string, name: string, thm: thm} -> unit) * (thm -> unit) wenzelm@6981: -> Proof.state -> Proof.state Seq.seq wenzelm@6981: val local_default_proof: ({kind: string, name: string, thm: thm} -> unit) * (thm -> unit) wenzelm@6736: -> Proof.state -> Proof.state Seq.seq wenzelm@6951: val global_qed: text option -> Proof.state -> theory * {kind: string, name: string, thm: thm} wenzelm@6934: val global_terminal_proof: text * text option wenzelm@6934: -> Proof.state -> theory * {kind: string, name: string, thm: thm} wenzelm@6532: val global_immediate_proof: Proof.state -> theory * {kind: string, name: string, thm: thm} wenzelm@6532: val global_default_proof: Proof.state -> theory * {kind: string, name: string, thm: thm} 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@6849: val METHOD = Proof.method; 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@7419: (* insert *) wenzelm@7419: wenzelm@7419: local wenzelm@5824: wenzelm@6981: fun cut_rule_tac raw_rule = wenzelm@6981: let wenzelm@6981: val rule = Drule.forall_intr_vars raw_rule; wenzelm@6981: val revcut_rl = Drule.incr_indexes_wrt [] [] [] [rule] Drule.revcut_rl; wenzelm@6981: in Tactic.rtac (rule COMP revcut_rl) THEN' Tactic.rotate_tac ~1 end; wenzelm@6981: wenzelm@7419: in wenzelm@5824: wenzelm@7419: fun insert_tac [] i = all_tac wenzelm@7419: | insert_tac facts i = EVERY (map (fn th => cut_rule_tac th i) facts); wenzelm@6981: wenzelm@7419: val insert = METHOD (ALLGOALS o insert_tac); wenzelm@7419: wenzelm@7419: end; wenzelm@5824: wenzelm@5824: wenzelm@6532: (* fold / unfold definitions *) wenzelm@6532: wenzelm@6532: val fold = METHOD0 o fold_goals_tac; wenzelm@6532: val unfold = METHOD0 o rewrite_goals_tac; wenzelm@6532: wenzelm@6532: wenzelm@7419: (* multi_resolve *) wenzelm@7419: wenzelm@7419: local wenzelm@7419: wenzelm@7419: fun res th i rule = wenzelm@7419: Thm.biresolution false [(false, th)] i rule handle THM _ => Seq.empty; wenzelm@7419: wenzelm@7419: fun multi_res _ [] rule = Seq.single rule wenzelm@7419: | multi_res i (th :: ths) rule = Seq.flat (Seq.map (res th i) (multi_res (i + 1) ths rule)); wenzelm@7419: wenzelm@7419: in wenzelm@7419: wenzelm@7419: val multi_resolve = multi_res 1; wenzelm@7419: fun multi_resolves facts rules = Seq.flat (Seq.map (multi_resolve facts) (Seq.of_list rules)); wenzelm@7419: wenzelm@7419: end; wenzelm@7419: wenzelm@7419: wenzelm@5824: (* rule *) wenzelm@5824: wenzelm@7419: local wenzelm@5824: wenzelm@7130: fun gen_rule_tac tac rules [] = tac rules wenzelm@7130: | gen_rule_tac tac erules facts = wenzelm@5824: let wenzelm@7419: val rules = multi_resolves facts erules; wenzelm@7130: fun tactic i state = Seq.flat (Seq.map (fn rule => tac [rule] i state) rules); wenzelm@7130: in tactic end; wenzelm@7130: wenzelm@7419: in wenzelm@7419: wenzelm@7130: val rule_tac = gen_rule_tac Tactic.resolve_tac; wenzelm@7130: val erule_tac = gen_rule_tac Tactic.eresolve_tac; wenzelm@5824: wenzelm@5824: fun rule rules = METHOD (FIRSTGOAL o rule_tac rules); wenzelm@7130: fun erule rules = METHOD (FIRSTGOAL o erule_tac rules); wenzelm@5824: wenzelm@7419: end; wenzelm@7419: wenzelm@7419: wenzelm@7419: (* assumption *) wenzelm@7419: wenzelm@7419: fun assumption_tac [] = assume_tac wenzelm@7419: | assumption_tac [fact] = resolve_tac [fact] wenzelm@7419: | assumption_tac _ = K no_tac; wenzelm@7419: wenzelm@7419: val assumption = METHOD (FIRSTGOAL o assumption_tac); wenzelm@7419: wenzelm@7419: wenzelm@7419: (* finish *) wenzelm@7419: wenzelm@7419: val FINISHED = FILTER (equal 0 o Thm.nprems_of); wenzelm@7419: val finish = METHOD (K (FINISHED (ALLGOALS assume_tac))); wenzelm@7419: 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@6546: val copy = I; 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@7367: fun print_meths verbose {space, meths} = wenzelm@5824: let wenzelm@5824: fun prt_meth (name, ((_, comment), _)) = Pretty.block wenzelm@6849: [Pretty.str (name ^ ":"), Pretty.brk 2, Pretty.str comment]; wenzelm@5824: in wenzelm@7367: if not verbose then () wenzelm@7367: else Pretty.writeln (Display.pretty_name_space ("method name space", space)); wenzelm@6849: Pretty.writeln (Pretty.big_list "methods:" wenzelm@6849: (map prt_meth (NameSpace.cond_extern_table space meths))) wenzelm@5824: end; wenzelm@7367: wenzelm@7367: fun print _ = print_meths true; wenzelm@5824: end; wenzelm@5824: wenzelm@5824: structure MethodsData = TheoryDataFun(MethodsDataArgs); wenzelm@5824: val print_methods = MethodsData.print; wenzelm@7367: val help_methods = MethodsDataArgs.print_meths false o MethodsData.get; wenzelm@5824: wenzelm@5824: wenzelm@5824: (* get methods *) wenzelm@5824: wenzelm@5916: exception METHOD_FAIL of (string * Position.T) * exn; wenzelm@5916: wenzelm@5824: fun method thy = wenzelm@5824: let wenzelm@5824: val {space, meths} = MethodsData.get thy; wenzelm@5824: wenzelm@5884: fun meth src = wenzelm@5884: let wenzelm@5884: val ((raw_name, _), pos) = Args.dest_src src; wenzelm@5884: val name = NameSpace.intern space raw_name; wenzelm@5884: in wenzelm@5824: (case Symtab.lookup (meths, name) of wenzelm@5824: None => error ("Unknown proof method: " ^ quote name ^ Position.str_of pos) wenzelm@5916: | Some ((mth, _), _) => transform_failure (curry METHOD_FAIL (name, pos)) (mth src)) 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@5884: wenzelm@5884: (** method syntax **) wenzelm@5824: wenzelm@5884: (* basic *) wenzelm@5884: wenzelm@5884: fun syntax (scan: (Proof.context * Args.T list -> 'a * (Proof.context * Args.T list))) = wenzelm@5884: Args.syntax "method" scan; wenzelm@5824: wenzelm@5884: fun no_args (x: Proof.method) src ctxt = #2 (syntax (Scan.succeed x) ctxt src); wenzelm@5884: wenzelm@5884: wenzelm@5884: (* sections *) wenzelm@5824: wenzelm@7268: type modifier = (Proof.context -> Proof.context) * Proof.context attribute; wenzelm@7268: wenzelm@7268: local wenzelm@7268: wenzelm@5884: fun sect ss = Scan.first (map (fn s => Scan.lift (s --| Args.$$$ ":")) ss); wenzelm@5884: fun thms ss = Scan.unless (sect ss) Attrib.local_thms; wenzelm@5884: fun thmss ss = Scan.repeat (thms ss) >> flat; wenzelm@5884: wenzelm@7268: fun apply (f, att) (ctxt, ths) = Thm.applys_attributes ((f ctxt, ths), [att]); wenzelm@5824: wenzelm@7268: fun section ss = (sect ss -- thmss ss) :-- (fn (m, ths) => Scan.depend (fn ctxt => wenzelm@7268: Scan.succeed (apply m (ctxt, ths)))) >> #2; wenzelm@5884: wenzelm@5884: fun sectioned args ss = args ss -- Scan.repeat (section ss); wenzelm@5884: wenzelm@7268: in wenzelm@5824: wenzelm@5884: fun sectioned_args args ss f src ctxt = wenzelm@5921: let val (ctxt', (x, _)) = syntax (sectioned args ss) ctxt src wenzelm@5921: in f x ctxt' end; wenzelm@5884: wenzelm@7268: fun default_sectioned_args m ss f src ctxt = wenzelm@7268: sectioned_args thmss ss (fn ths => fn ctxt' => f (#1 (apply m (ctxt', ths)))) src ctxt; wenzelm@5884: wenzelm@5884: fun only_sectioned_args ss f = sectioned_args (K (Scan.succeed ())) ss (fn () => f); wenzelm@7268: wenzelm@5884: fun thms_args f = sectioned_args thmss [] (fn ths => fn _ => f ths); wenzelm@5824: wenzelm@7268: end; wenzelm@7268: 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: Repeat1 of text; 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 (Repeat1 txt) = Seq.REPEAT1 (eval txt); wenzelm@5824: in eval text state end; wenzelm@5824: wenzelm@6404: fun named_method name = Source (Args.src ((name, []), Position.none)); wenzelm@6404: 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@5884: fun then_tac text state = wenzelm@5824: state wenzelm@5824: |> Proof.goal_facts Proof.the_facts wenzelm@5824: |> refine text; wenzelm@5824: wenzelm@5824: wenzelm@6404: (* structured proof steps *) wenzelm@5824: wenzelm@6404: val default_text = named_method "default"; wenzelm@6404: val finish_text = named_method "finish"; wenzelm@5824: wenzelm@6872: wenzelm@5824: fun proof opt_text state = wenzelm@5824: state wenzelm@5824: |> Proof.assert_backward wenzelm@6404: |> refine (if_none opt_text default_text) wenzelm@5824: |> Seq.map Proof.enter_forward; wenzelm@5824: wenzelm@6404: fun local_qed opt_text = Proof.local_qed (refine (if_none opt_text finish_text)); wenzelm@6934: fun local_terminal_proof (text, opt_text) pr = Seq.THEN (proof (Some text), local_qed opt_text pr); wenzelm@7419: val local_immediate_proof = local_terminal_proof (Basic (K assumption), None); wenzelm@6934: val local_default_proof = local_terminal_proof (default_text, None); wenzelm@5824: wenzelm@6872: wenzelm@6951: fun global_qeds opt_text = Proof.global_qed (refine (if_none opt_text finish_text)); wenzelm@5824: wenzelm@6951: fun global_qed opt_text state = wenzelm@6872: state wenzelm@6951: |> global_qeds opt_text wenzelm@6872: |> Proof.check_result "Failed to finish proof" state wenzelm@6872: |> Seq.hd; wenzelm@6872: wenzelm@6934: fun global_terminal_proof (text, opt_text) state = wenzelm@6872: state wenzelm@6872: |> proof (Some text) wenzelm@6872: |> Proof.check_result "Terminal proof method failed" state wenzelm@6951: |> (Seq.flat o Seq.map (global_qeds opt_text)) wenzelm@6872: |> Proof.check_result "Failed to finish proof (after successful terminal method)" state wenzelm@6872: |> Seq.hd; wenzelm@6872: wenzelm@7419: val global_immediate_proof = global_terminal_proof (Basic (K assumption), None); wenzelm@6934: val global_default_proof = global_terminal_proof (default_text, None); 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@7419: ("-", no_args insert, "insert facts, nothing else"), wenzelm@6532: ("fold", thms_args fold, "fold definitions"), wenzelm@6532: ("unfold", thms_args unfold, "unfold definitions"), wenzelm@7130: ("rule", thms_args rule, "apply some rule"), wenzelm@7419: ("erule", thms_args erule, "apply some erule (improper!)"), wenzelm@7419: ("assumption", no_args assumption, "proof by assumption"), wenzelm@7419: ("finish", no_args finish, "finish proof by assumption")]; 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;