X-Git-Url: http://matita.cs.unibo.it/gitweb/?p=helm.git;a=blobdiff_plain;f=helm%2Focaml%2Ftactics%2Ftacticals.ml;fp=helm%2Focaml%2Ftactics%2Ftacticals.ml;h=a674fe31344a1f840971afececcc9b5a0f19fa61;hp=0000000000000000000000000000000000000000;hb=792b5d29ebae8f917043d9dd226692919b5d6ca1;hpb=a14a8c7637fd0b95e9d4deccb20c6abc98e8f953 diff --git a/helm/ocaml/tactics/tacticals.ml b/helm/ocaml/tactics/tacticals.ml new file mode 100644 index 000000000..a674fe313 --- /dev/null +++ b/helm/ocaml/tactics/tacticals.ml @@ -0,0 +1,351 @@ +(* Copyright (C) 2002, HELM Team. + * + * This file is part of HELM, an Hypertextual, Electronic + * Library of Mathematics, developed at the Computer Science + * Department, University of Bologna, Italy. + * + * HELM is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * HELM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with HELM; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + * + * For details, see the HELM World-Wide-Web page, + * http://cs.unibo.it/helm/. + *) + +(* $Id$ *) + +(* open CicReduction +open ProofEngineTypes +open UriManager *) + +(** DEBUGGING *) + + (** perform debugging output? *) +let debug = false +let debug_print = fun _ -> () + + (** debugging print *) +let info s = debug_print (lazy ("TACTICALS INFO: " ^ (Lazy.force s))) + +let id_tac = + let id_tac (proof,goal) = + let _, metasenv, _, _ = proof in + let _, _, _ = CicUtil.lookup_meta goal metasenv in + (proof,[goal]) + in + ProofEngineTypes.mk_tactic id_tac + +let fail_tac = + let fail_tac (proof,goal) = + let _, metasenv, _, _ = proof in + let _, _, _ = CicUtil.lookup_meta goal metasenv in + raise (ProofEngineTypes.Fail (lazy "fail tactical")) + in + ProofEngineTypes.mk_tactic fail_tac + +type goal = ProofEngineTypes.goal + + (** TODO needed until tactics start returning both opened and closed goals + * First part of the function performs a diff among goals ~before tactic + * application and ~after it. Second part will add as both opened and closed + * the goals which are returned as opened by the tactic *) +let goals_diff ~before ~after ~opened = + let sort_opened opened add = + opened @ (List.filter (fun g -> not (List.mem g opened)) add) + in + let remove = + List.fold_left + (fun remove e -> if List.mem e after then remove else e :: remove) + [] before + in + let add = + List.fold_left + (fun add e -> if List.mem e before then add else e :: add) + [] + after + in + let add, remove = (* adds goals which have been both opened _and_ closed *) + List.fold_left + (fun (add, remove) opened_goal -> + if List.mem opened_goal before + then opened_goal :: add, opened_goal :: remove + else add, remove) + (add, remove) + opened + in + sort_opened opened add, remove + +module type T = +sig + type tactic + val first: tactics: (string * tactic) list -> tactic + val thens: start: tactic -> continuations: tactic list -> tactic + val then_: start: tactic -> continuation: tactic -> tactic + val seq: tactics: tactic list -> tactic + val repeat_tactic: tactic: tactic -> tactic + val do_tactic: n: int -> tactic: tactic -> tactic + val try_tactic: tactic: tactic -> tactic + val solve_tactics: tactics: (string * tactic) list -> tactic + + val tactic: tactic -> tactic + val skip: tactic + val dot: tactic + val semicolon: tactic + val branch: tactic + val shift: tactic + val pos: int -> tactic + val merge: tactic + val focus: int list -> tactic + val unfocus: tactic +end + +module Make (S: Continuationals.Status) : T with type tactic = S.tactic = +struct + module C = Continuationals.Make (S) + + type tactic = S.tactic + + let fold_eval status ts = + let istatus = + List.fold_left (fun istatus t -> S.focus ~-1 (C.eval t istatus)) status ts + in + S.inject istatus + + (** + naive implementation of ORELSE tactical, try a sequence of tactics in turn: + if one fails pass to the next one and so on, eventually raises (failure "no + tactics left") + *) + let first ~tactics = + let rec first ~(tactics: (string * tactic) list) istatus = + info (lazy "in Tacticals.first"); + match tactics with + | (descr, tac)::tactics -> + info (lazy ("Tacticals.first IS TRYING " ^ descr)); + (try + let res = S.apply_tactic tac istatus in + info (lazy ("Tacticals.first: " ^ descr ^ " succedeed!!!")); + res + with + e -> + match e with + | (ProofEngineTypes.Fail _) + | (CicTypeChecker.TypeCheckerFailure _) + | (CicUnification.UnificationFailure _) -> + info (lazy ( + "Tacticals.first failed with exn: " ^ + Printexc.to_string e)); + first ~tactics istatus + | _ -> raise e) (* [e] must not be caught ; let's re-raise it *) + | [] -> raise (ProofEngineTypes.Fail (lazy "first: no tactics left")) + in + S.mk_tactic (first ~tactics) + + let thens ~start ~continuations = + S.mk_tactic + (fun istatus -> + fold_eval istatus + ([ C.Tactical (C.Tactic start); C.Branch ] + @ (HExtlib.list_concat ~sep:[ C.Shift ] + (List.map (fun t -> [ C.Tactical (C.Tactic t) ]) continuations)) + @ [ C.Merge ])) + + let then_ ~start ~continuation = + S.mk_tactic + (fun istatus -> + let ostatus = C.eval (C.Tactical (C.Tactic start)) istatus in + let opened,closed = S.goals ostatus in + match opened with + [] -> ostatus + | _ -> + fold_eval (S.focus ~-1 ostatus) + [ C.Semicolon; + C.Tactical (C.Tactic continuation) ]) + + let seq ~tactics = + S.mk_tactic + (fun istatus -> + fold_eval istatus + (HExtlib.list_concat ~sep:[ C.Semicolon ] + (List.map (fun t -> [ C.Tactical (C.Tactic t) ]) tactics))) + + (* TODO: x debug: i due tatticali seguenti non contano quante volte hanno + * applicato la tattica *) + + let rec step f output_status opened closed = + match opened with + | [] -> output_status, [], closed + | head :: tail -> + let status = S.focus head output_status in + let output_status' = f status in + let opened', closed' = S.goals output_status' in + let output_status'', opened'', closed'' = + step f output_status' tail [] + in + output_status'', opened' @ opened'', closed' @ closed'' + + (* This keep on appling tactic until it fails. When generates more + * than one goal, you have a tree of application on the tactic, repeat_tactic + * works in depth on this tree *) + let repeat_tactic ~tactic = + let rec repeat_tactic ~tactic status = + info (lazy "in repeat_tactic"); + try + let output_status = S.apply_tactic tactic status in + let opened, closed = S.goals output_status in + let output_status, opened', closed' = + step (repeat_tactic ~tactic) output_status opened closed + in + S.set_goals (opened', closed') output_status + with + (ProofEngineTypes.Fail _) as e -> + info (lazy + ("Tacticals.repeat_tactic failed after nth time with exception: " + ^ Printexc.to_string e)); + S.apply_tactic S.id_tactic status + in + S.mk_tactic (repeat_tactic ~tactic) + + (* This tries to apply tactic n times *) + let do_tactic ~n ~tactic = + let rec do_tactic ~n ~tactic status = + if n = 0 then + S.apply_tactic S.id_tactic status + else + try + let output_status = S.apply_tactic tactic status in + let opened, closed = S.goals output_status in + let output_status, opened', closed' = + step (do_tactic ~n:(n-1) ~tactic) output_status opened closed + in + S.set_goals (opened', closed') output_status + with + (ProofEngineTypes.Fail _) as e -> + info (lazy + ("Tacticals.do_tactic failed after nth time with exception: " + ^ Printexc.to_string e)) ; + S.apply_tactic S.id_tactic status + in + S.mk_tactic (do_tactic ~n ~tactic) + + (* This applies tactic and catches its possible failure *) + let try_tactic ~tactic = + let rec try_tactic ~tactic status = + info (lazy "in Tacticals.try_tactic"); + try + S.apply_tactic tactic status + with + (ProofEngineTypes.Fail _) as e -> + info (lazy ( + "Tacticals.try_tactic failed with exn: " ^ Printexc.to_string e)); + S.apply_tactic S.id_tactic status + in + S.mk_tactic (try_tactic ~tactic) + + (* This tries tactics until one of them doesn't _solve_ the goal *) + (* TODO: si puo' unificare le 2(due) chiamate ricorsive? *) + let solve_tactics ~tactics = + let rec solve_tactics ~(tactics: (string * tactic) list) status = + info (lazy "in Tacticals.solve_tactics"); + match tactics with + | (descr, currenttactic)::moretactics -> + info (lazy ("Tacticals.solve_tactics is trying " ^ descr)); + (try + let output_status = S.apply_tactic currenttactic status in + let opened, closed = S.goals output_status in + match opened with + | [] -> info (lazy ("Tacticals.solve_tactics: " ^ descr ^ + " solved the goal!!!")); + (* questo significa che non ci sono piu' goal, o che current_tactic non ne ha + * aperti di nuovi? (la 2a!) ##### nel secondo caso basta per dire che + * solve_tactics has solved the goal? (si!) *) + output_status + | _ -> info (lazy ("Tacticals.solve_tactics: try the next tactic")); + solve_tactics ~tactics:(moretactics) status + with + (ProofEngineTypes.Fail _) as e -> + info (lazy ( + "Tacticals.solve_tactics: current tactic failed with exn: " + ^ Printexc.to_string e)); + solve_tactics ~tactics status + ) + | [] -> + raise (ProofEngineTypes.Fail + (lazy "solve_tactics cannot solve the goal")) + in + S.mk_tactic (solve_tactics ~tactics) + + let cont_proxy cont = S.mk_tactic (C.eval cont) + + let tactic t = cont_proxy (C.Tactical (C.Tactic t)) + let skip = cont_proxy (C.Tactical C.Skip) + let dot = cont_proxy C.Dot + let semicolon = cont_proxy C.Semicolon + let branch = cont_proxy C.Branch + let shift = cont_proxy C.Shift + let pos i = cont_proxy (C.Pos i) + let merge = cont_proxy C.Merge + let focus goals = cont_proxy (C.Focus goals) + let unfocus = cont_proxy C.Unfocus +end + +module ProofEngineStatus = +struct + module Stack = Continuationals.Stack + + type input_status = + ProofEngineTypes.status (* (proof, goal) *) * Stack.t + + type output_status = + (ProofEngineTypes.proof * goal list * goal list) * Stack.t + + type tactic = ProofEngineTypes.tactic + + let id_tactic = id_tac + + let mk_tactic f = + ProofEngineTypes.mk_tactic + (fun (proof, goal) as pstatus -> + let stack = [ [ 1, Stack.Open goal ], [], [], `NoTag ] in + let istatus = pstatus, stack in +(* let ostatus = f istatus in + let ((proof, opened, _), _) = ostatus in *) + let (proof, _, _), stack = f istatus in + let opened = Continuationals.Stack.open_goals stack in + proof, opened) + + let apply_tactic tac ((proof, _) as pstatus, stack) = + let proof', opened = ProofEngineTypes.apply_tactic tac pstatus in +(* let _ = prerr_endline ("goal aperti dalla tattica " ^ String.concat "," (List.map string_of_int opened)) in *) + let before = ProofEngineTypes.goals_of_proof proof in + let after = ProofEngineTypes.goals_of_proof proof' in + let opened_goals, closed_goals = goals_diff ~before ~after ~opened in +(* let _ = prerr_endline ("goal ritornati dalla tattica " ^ String.concat "," (List.map string_of_int opened_goals)) in *) + (proof', opened_goals, closed_goals), stack + + let goals ((_, opened, closed), _) = opened, closed + let set_goals (opened, closed) ((proof, _, _), stack) = + (proof, opened, closed), stack + + let get_stack = snd + let set_stack stack (opstatus, _) = opstatus, stack + + let inject ((proof, _), stack) = ((proof, [], []), stack) + let focus goal ((proof, _, _), stack) = (proof, goal), stack +end + +module ProofEngineTacticals = Make (ProofEngineStatus) + +include ProofEngineTacticals +