* http://helm.cs.unibo.it/
*)
-let compose_tac ?howmany ?mk_fresh_name_callback t1 t2 (proof, goal) =
+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 rec count_pi = function Cic.Prod (_,_,t) -> count_pi t + 1 | _ -> 0 in
- let rec generate arity menv acc =
- if arity < 0 then acc, menv
- else
+ 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, menv, _ =
- CloseCoercionGraph.generate_composite t1 t2 context menv
- CicUniv.oblivion_ugraph arity false
+ let t, menv1, _ =
+ CloseCoercionGraph.generate_composite t2 t1 context menv
+ CicUniv.oblivion_ugraph saturations_t2 saturations_t1
in
- generate (arity - 1) menv (t::acc)
+ assert (List.length menv1 = List.length menv);
+ generate tl menv (t::acc)
with
- | CloseCoercionGraph.UnableToCompose -> generate (arity - 1) menv acc
+ | CloseCoercionGraph.UnableToCompose -> generate tl menv acc
in
- let terms, metasenv = generate (count_pi ty1) metasenv [] 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 ->
proof,List.hd gl)
(proof,goal) terms
in
- ProofEngineTypes.apply_tactic
- (PrimitiveTactics.intros_tac ?howmany ?mk_fresh_name_callback ())
- (proof,goal)
+ (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 t1 t2 =
+let compose_tac ?howmany ?mk_fresh_name_callback times t1 t2 =
ProofEngineTypes.mk_tactic
- (compose_tac ?howmany ?mk_fresh_name_callback t1 t2)
+ (compose_tac ?howmany ?mk_fresh_name_callback times t1 t2)
;;