(* 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/. *) open CicReduction open ProofEngineTypes open UriManager (** DEBUGGING *) (** perform debugging output? *) let debug = false let debug_print = fun _ -> () (** debugging print *) let warn s = if debug then debug_print ("TACTICALS WARNING: " ^ s) (** TACTIC{,AL}S *) (* not a tactical, but it's used only here (?) *) let id_tac = let tac (proof,goal) = (proof,[goal]) in mk_tactic tac (** 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") TODO warning: not tail recursive due to "try .. with" boxing Galla: is this exactly Coq's "First"? *) let try_tactics ~tactics = let rec try_tactics ~(tactics: (string * tactic) list) status = warn "in Tacticals.try_tactics"; match tactics with | (descr, tac)::tactics -> warn ("Tacticals.try_tactics IS TRYING " ^ descr); (try let res = apply_tactic tac status in warn ("Tacticals.try_tactics: " ^ descr ^ " succedeed!!!"); res with e -> match e with (Fail _) | (CicTypeChecker.TypeCheckerFailure _) | (CicUnification.UnificationFailure _) -> warn ( "Tacticals.try_tactics failed with exn: " ^ Printexc.to_string e); try_tactics ~tactics status | _ -> raise e (* [e] must not be caught ; let's re-raise it *) ) | [] -> raise (Fail "try_tactics: no tactics left") in mk_tactic (try_tactics ~tactics) let thens ~start ~continuations = let thens ~start ~continuations status = let (proof,new_goals) = apply_tactic start status in try List.fold_left2 (fun (proof,goals) goal tactic -> let (proof',new_goals') = apply_tactic tactic (proof,goal) in (proof',goals@new_goals') ) (proof,[]) new_goals continuations with Invalid_argument _ -> (* FG: more debugging information *) let debug = Printf.sprintf "thens: expected %i new goals, found %i" (List.length continuations) (List.length new_goals) in raise (Fail debug) in mk_tactic (thens ~start ~continuations ) let then_ ~start ~continuation = let then_ ~start ~continuation status = let (proof,new_goals) = apply_tactic start status in List.fold_left (fun (proof,goals) goal -> let (proof',new_goals') = apply_tactic continuation (proof,goal) in (proof',goals@new_goals') ) (proof,[]) new_goals in mk_tactic (then_ ~start ~continuation) let rec seq ~tactics = match tactics with | [] -> assert false | [tac] -> tac | hd :: tl -> then_ ~start:hd ~continuation:(seq ~tactics:tl) (* TODO: x debug: i due tatticali seguenti non contano quante volte hanno applicato la tattica *) (* 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 = warn "in repeat_tactic"; try let (proof, goallist) = apply_tactic tactic status in let rec step proof goallist = match goallist with [] -> (proof, []) | head::tail -> let (proof', goallist') = repeat_tactic ~tactic (proof, head) in let (proof'', goallist'') = step proof' tail in proof'', goallist'@goallist'' in step proof goallist with (Fail _) as e -> warn ("Tacticals.repeat_tactic failed after nth time with exception: " ^ Printexc.to_string e) ; apply_tactic id_tac status in mk_tactic (repeat_tactic ~tactic) ;; (* This tries to apply tactic n times *) let do_tactic ~n ~tactic = let rec do_tactic ~n ~tactic status = warn "in do_tactic"; try let (proof, goallist) = if (n>0) then apply_tactic tactic status else apply_tactic id_tac status in (* else (proof, []) in *) (* perche' non va bene questo? stessa questione di ##### ? *) let rec step proof goallist = match goallist with [] -> (proof, []) | head::tail -> let (proof', goallist') = do_tactic ~n:(n-1) ~tactic (proof, head) in let (proof'', goallist'') = step proof' tail in proof'', goallist'@goallist'' in step proof goallist with (Fail _) as e -> warn ("Tacticals.do_tactic failed after nth time with exception: " ^ Printexc.to_string e) ; apply_tactic id_tac status in mk_tactic (do_tactic ~n ~tactic) ;; (* This applies tactic and catches its possible failure *) let try_tactic ~tactic = let rec try_tactic ~tactic status = warn "in Tacticals.try_tactic"; try apply_tactic tactic status with (Fail _) as e -> warn ( "Tacticals.try_tactic failed with exn: " ^ Printexc.to_string e); apply_tactic id_tac status in mk_tactic (try_tactic ~tactic) ;; let fail = mk_tactic (fun _ -> raise (Fail "fail tactical")) (* 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 = warn "in Tacticals.solve_tactics"; match tactics with | (descr, currenttactic)::moretactics -> warn ("Tacticals.solve_tactics is trying " ^ descr); (try let (proof, goallist) = apply_tactic currenttactic status in match goallist with [] -> warn ("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!) *) (proof, goallist) | _ -> warn ("Tacticals.solve_tactics: try the next tactic"); solve_tactics ~tactics:(moretactics) status with (Fail _) as e -> warn ("Tacticals.solve_tactics: current tactic failed with exn: " ^ Printexc.to_string e); solve_tactics ~tactics status ) | [] -> raise (Fail "solve_tactics cannot solve the goal"); apply_tactic id_tac status in mk_tactic (solve_tactics ~tactics) ;; (** tattica di prova per debuggare i tatticali *) (* let thens' ~start ~continuations status = let (proof,new_goals) = start status in try List.fold_left2 (fun (proof,goals) goal tactic -> let (proof',new_goals') = tactic (proof,goal) in (proof',goals@new_goals') ) (proof,[]) new_goals continuations with Invalid_argument _ -> raise (Fail "thens: wrong number of new goals") let prova_tac = let apply_T_tac status = let (proof, goal) = status in let curi,metasenv,pbo,pty = proof in let metano,context,gty = CicUtil.lookup_meta goal metasenv in let rel = let rec find n = function [] -> assert false | (Some (Cic.Name name,_))::_ when name = "T" -> n | _::tl -> find (n+1) tl in debug_print ("eseguo find"); find 1 context in debug_print ("eseguo apply"); apply_tac ~term:(Cic.Rel rel) status in (* do_tactic ~n:2 *) repeat_tactic ~tactic: (then_ ~start:(intros_tac ~name:"pippo") ~continuation:(thens' ~start:apply_T_tac ~continuations:[id_tac ; apply_tac ~term:(Cic.Rel 1)])) (* id_tac *) ;; *)