(* Copyright (C) 2005, 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://helm.cs.unibo.it/ *) let debug = false;; let debug_print = if not debug then (fun _ -> ()) else (fun s -> prerr_endline (Lazy.force s)) ;; let rec count_pi = function Cic.Prod (_,_,t) -> count_pi t + 1 | _ -> 0 ;; let compose_core t2 t1 (proof, goal) = let _,metasenv,_subst,_,_,_ = proof in let _,context,_ = CicUtil.lookup_meta goal metasenv in let ty1,_ = CicTypeChecker.type_of_aux' metasenv context t1 CicUniv.oblivion_ugraph in let ty2,_ = CicTypeChecker.type_of_aux' metasenv context t2 CicUniv.oblivion_ugraph in let saturated_ty2, menv_for_saturated_ty2, args_t2 = let maxm = CicMkImplicit.new_meta metasenv [] in let ty2, menv, args, _ = TermUtil.saturate_term ~delta:false maxm metasenv context ty2 0 in ty2, menv, args in let saturations_t2 = let rec aux n = function | Cic.Meta (i,_)::tl -> let _,c,ty = CicUtil.lookup_meta i menv_for_saturated_ty2 in if fst (CicReduction.are_convertible c ty (Cic.Sort Cic.Prop) CicUniv.oblivion_ugraph) then n else aux (n+1) tl | _::tl -> aux (n+1) tl | [] -> n+1 in List.length args_t2 - aux 0 args_t2 +1 in debug_print (lazy("saturated_ty2: "^CicMetaSubst.ppterm_in_context [] ~metasenv:menv_for_saturated_ty2 saturated_ty2 context ^ " saturations_t2:" ^ string_of_int saturations_t2)); (* unifies t with saturated_ty2 and gives back a fresh meta of type t *) let unif menv t = let m, menv2 = let n = CicMkImplicit.new_meta menv [] in let irl = CicMkImplicit.identity_relocation_list_for_metavariable context in Cic.Meta (n,irl), ((n,context,t)::menv) in try let _ = CicUnification.fo_unif menv context t saturated_ty2 CicUniv.oblivion_ugraph in true, menv2, m with | CicUnification.UnificationFailure _ | CicUnification.Uncertain _ -> false, menv2, m in (* check which "positions" in the input arrow unifies with saturated_ty2 *) let rec positions menv cur saturations = function | Cic.Prod (n,s,t) -> let b, newmenv, sb = unif menv s in if b then (saturations - cur - 1) :: (positions newmenv (cur + 1) saturations (CicSubstitution.subst sb t)) else positions newmenv (cur + 1) saturations (CicSubstitution.subst sb t) | _ -> [] in (* position is a list of arities, that is if t1 : a -> b -> c and saturations * is 0 then the computed term will be (t1 ? t2) of type a -> c if saturations * is 1 then (t1 t2 ?) of type b -> c *) let rec generate positions menv acc = match positions with | [] -> acc, menv | saturations_t1::tl -> try let t, menv1, _ = CloseCoercionGraph.generate_composite t2 t1 context menv CicUniv.oblivion_ugraph saturations_t2 saturations_t1 in assert (List.length menv1 = List.length menv); generate tl menv (t::acc) with | CloseCoercionGraph.UnableToCompose -> generate tl menv acc in let terms, metasenv = generate (positions menv_for_saturated_ty2 0 (count_pi ty1) ty1) metasenv [] in (* the new proof has the resulting metasenv (shouldn't it be the same?) *) let proof = let uri, _, _subst, bo, ty, attrs = proof in uri, metasenv, _subst, bo, ty, attrs in (* now we have the terms, we generalize them and intros them *) let proof, goal = List.fold_left (fun (proof,goal) t -> let lazy_of t = ProofEngineTypes.const_lazy_term t in let proof, gl = ProofEngineTypes.apply_tactic (VariousTactics.generalize_tac (Some (lazy_of t), [], None)) (proof,goal) in assert(List.length gl = 1); proof,List.hd gl) (proof,goal) terms in (proof, goal), List.length terms ;; let compose_tac ?howmany ?mk_fresh_name_callback n t1 t2 proofstatus = let ((proof, goal), k), n = match t2 with | Some t2 -> compose_core t1 t2 proofstatus, n-1 | None -> let k = let proof, goal = proofstatus in let _,metasenv,subst,_,_,_ = proof in let _,_,ty = CicUtil.lookup_meta goal metasenv in count_pi (CicMetaSubst.apply_subst subst ty) in (proofstatus, k), n in let (proof, goal), k = (* fix iterates n times the composition *) let rec fix proofstatus k t = function | 0 -> proofstatus, k | n -> let t = CicSubstitution.lift k t in let proof, gl = ProofEngineTypes.apply_tactic (PrimitiveTactics.intros_tac ~howmany:k ?mk_fresh_name_callback ()) proofstatus in assert (List.length gl = 1); let goal = List.hd gl in let k, proofstatus = (* aux compose t with every previous result *) let rec aux k proofstatus = function | 0 -> k, proofstatus | n -> let (proof, goal), k1 = compose_core t (Cic.Rel n) proofstatus in aux (k+k1) (proof, goal) (n-1) in aux 0 (proof, goal) k in fix proofstatus k t (n-1) in fix (proof, goal) k t1 n in let howmany = match howmany with | None -> None | Some i -> if i - k < 0 then (* we should generalize back and clear *) Some 0 else Some (i - k) in ProofEngineTypes.apply_tactic (PrimitiveTactics.intros_tac ?howmany ?mk_fresh_name_callback ()) (proof,goal) ;; let compose_tac ?howmany ?mk_fresh_name_callback times t1 t2 = ProofEngineTypes.mk_tactic (compose_tac ?howmany ?mk_fresh_name_callback times t1 t2) ;;