From 6b649aba925b6f7462da07599fe67ebb12a3460e Mon Sep 17 00:00:00 2001 From: Samuel Mimram Date: Wed, 28 Jul 2004 21:54:47 +0000 Subject: Imported Upstream version 8.0pl1 --- pretyping/tacred.ml | 953 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 953 insertions(+) create mode 100644 pretyping/tacred.ml (limited to 'pretyping/tacred.ml') diff --git a/pretyping/tacred.ml b/pretyping/tacred.ml new file mode 100644 index 00000000..7e79a4fe --- /dev/null +++ b/pretyping/tacred.ml @@ -0,0 +1,953 @@ +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* None & cb.const_opaque then + errorlabstrm "set_transparent_const" + (str "Cannot make" ++ spc () ++ + Nametab.pr_global_env Idset.empty (ConstRef sp) ++ + spc () ++ str "transparent because it was declared opaque."); + Conv_oracle.set_transparent_const sp + +let set_opaque_var = Conv_oracle.set_opaque_var +let set_transparent_var = Conv_oracle.set_transparent_var + +let _ = + Summary.declare_summary "Transparent constants and variables" + { Summary.freeze_function = Conv_oracle.freeze; + Summary.unfreeze_function = Conv_oracle.unfreeze; + Summary.init_function = Conv_oracle.init; + Summary.survive_module = false; + Summary.survive_section = false } + +let is_evaluable env ref = + match ref with + EvalConstRef kn -> + let (ids,kns) = Conv_oracle.freeze() in + KNpred.mem kn kns & + let cb = Environ.lookup_constant kn env in + cb.const_body <> None & not cb.const_opaque + | EvalVarRef id -> + let (ids,sps) = Conv_oracle.freeze() in + Idpred.mem id ids & + let (_,value,_) = Environ.lookup_named id env in + value <> None + +type evaluable_reference = + | EvalConst of constant + | EvalVar of identifier + | EvalRel of int + | EvalEvar of existential + +let mkEvalRef = function + | EvalConst cst -> mkConst cst + | EvalVar id -> mkVar id + | EvalRel n -> mkRel n + | EvalEvar ev -> mkEvar ev + +let isEvalRef env c = match kind_of_term c with + | Const sp -> is_evaluable env (EvalConstRef sp) + | Var id -> is_evaluable env (EvalVarRef id) + | Rel _ | Evar _ -> true + | _ -> false + +let destEvalRef c = match kind_of_term c with + | Const cst -> EvalConst cst + | Var id -> EvalVar id + | Rel n -> EvalRel n + | Evar ev -> EvalEvar ev + | _ -> anomaly "Not an evaluable reference" + +let reference_opt_value sigma env = function + | EvalConst cst -> constant_opt_value env cst + | EvalVar id -> + let (_,v,_) = lookup_named id env in + v + | EvalRel n -> + let (_,v,_) = lookup_rel n env in + option_app (lift n) v + | EvalEvar ev -> existential_opt_value sigma ev + +exception NotEvaluable +let reference_value sigma env c = + match reference_opt_value sigma env c with + | None -> raise NotEvaluable + | Some d -> d + +(************************************************************************) +(* Reduction of constant hiding fixpoints (e.g. for Simpl). The trick *) +(* is to reuse the name of the function after reduction of the fixpoint *) + +type constant_evaluation = + | EliminationFix of int * (int * (int * constr) list * int) + | EliminationMutualFix of + int * evaluable_reference * + (evaluable_reference option array * (int * (int * constr) list * int)) + | EliminationCases of int + | NotAnElimination + +(* We use a cache registered as a global table *) + + +module CstOrdered = + struct + type t = constant + let compare = Pervasives.compare + end +module Cstmap = Map.Make(CstOrdered) + +let eval_table = ref Cstmap.empty + +type frozen = (int * constant_evaluation) Cstmap.t + +let init () = + eval_table := Cstmap.empty + +let freeze () = + !eval_table + +let unfreeze ct = + eval_table := ct + +let _ = + Summary.declare_summary "evaluation" + { Summary.freeze_function = freeze; + Summary.unfreeze_function = unfreeze; + Summary.init_function = init; + Summary.survive_module = false; + Summary.survive_section = false } + + +(* Check that c is an "elimination constant" + [xn:An]..[x1:A1](

MutCase (Rel i) of f1..fk end g1 ..gp) + or [xn:An]..[x1:A1](Fix(f|t) (Rel i1) ..(Rel ip)) + with i1..ip distinct variables not occuring in t + keep relevenant information ([i1,Ai1;..;ip,Aip],n,b) + with b = true in case of a fixpoint in order to compute + an equivalent of Fix(f|t)[xi<-ai] as + [yip:Bip]..[yi1:Bi1](F bn..b1) + == [yip:Bip]..[yi1:Bi1](Fix(f|t)[xi<-ai] (Rel 1)..(Rel p)) + with bj=aj if j<>ik and bj=(Rel c) and Bic=Aic[xn..xic-1 <- an..aic-1] *) + +let check_fix_reversibility labs args ((lv,i),(_,tys,bds)) = + let n = List.length labs in + let nargs = List.length args in + if nargs > n then raise Elimconst; + let nbfix = Array.length bds in + let li = + List.map + (function d -> match kind_of_term d with + | Rel k -> + if + array_for_all (noccurn k) tys + && array_for_all (noccurn (k+nbfix)) bds + then + (k, List.nth labs (k-1)) + else + raise Elimconst + | _ -> + raise Elimconst) args + in + if list_distinct (List.map fst li) then + let k = lv.(i) in + if k < nargs then +(* Such an optimisation would need eta-expansion + let p = destRel (List.nth args k) in + EliminationFix (n-p+1,(nbfix,li,n)) +*) + EliminationFix (n,(nbfix,li,n)) + else + EliminationFix (n-nargs+lv.(i)+1,(nbfix,li,n)) + else + raise Elimconst + +(* Heuristic to look if global names are associated to other + components of a mutual fixpoint *) + +let invert_name labs l na0 env sigma ref = function + | Name id -> + if na0 <> Name id then + let refi = match ref with + | EvalRel _ | EvalEvar _ -> None + | EvalVar id' -> Some (EvalVar id) + | EvalConst kn -> + let (mp,dp,_) = repr_kn kn in + Some (EvalConst (make_kn mp dp (label_of_id id))) in + match refi with + | None -> None + | Some ref -> + match reference_opt_value sigma env ref with + | None -> None + | Some c -> + let labs',ccl = decompose_lam c in + let _, l' = whd_betalet_stack ccl in + let labs' = List.map snd labs' in + if labs' = labs & l = l' then Some ref else None + else Some ref + | Anonymous -> None (* Actually, should not occur *) + +(* [compute_consteval_direct] expand all constant in a whole, but + [compute_consteval_mutual_fix] only one by one, until finding the + last one before the Fix if the latter is mutually defined *) + +let compute_consteval_direct sigma env ref = + let rec srec env n labs c = + let c',l = whd_betadelta_stack env sigma c in + match kind_of_term c' with + | Lambda (id,t,g) when l=[] -> + srec (push_rel (id,None,t) env) (n+1) (t::labs) g + | Fix fix -> + (try check_fix_reversibility labs l fix + with Elimconst -> NotAnElimination) + | Case (_,_,d,_) when isRel d -> EliminationCases n + | _ -> NotAnElimination + in + match reference_opt_value sigma env ref with + | None -> NotAnElimination + | Some c -> srec env 0 [] c + +let compute_consteval_mutual_fix sigma env ref = + let rec srec env minarg labs ref c = + let c',l = whd_betalet_stack c in + let nargs = List.length l in + match kind_of_term c' with + | Lambda (na,t,g) when l=[] -> + srec (push_rel (na,None,t) env) (minarg+1) (t::labs) ref g + | Fix ((lv,i),(names,_,_) as fix) -> + (* Last known constant wrapping Fix is ref = [labs](Fix l) *) + (match compute_consteval_direct sigma env ref with + | NotAnElimination -> (*Above const was eliminable but this not!*) + NotAnElimination + | EliminationFix (minarg',infos) -> + let refs = + Array.map + (invert_name labs l names.(i) env sigma ref) names in + let new_minarg = max (minarg'+minarg-nargs) minarg' in + EliminationMutualFix (new_minarg,ref,(refs,infos)) + | _ -> assert false) + | _ when isEvalRef env c' -> + (* Forget all \'s and args and do as if we had started with c' *) + let ref = destEvalRef c' in + (match reference_opt_value sigma env ref with + | None -> anomaly "Should have been trapped by compute_direct" + | Some c -> srec env (minarg-nargs) [] ref c) + | _ -> (* Should not occur *) NotAnElimination + in + match reference_opt_value sigma env ref with + | None -> (* Should not occur *) NotAnElimination + | Some c -> srec env 0 [] ref c + +let compute_consteval sigma env ref = + match compute_consteval_direct sigma env ref with + | EliminationFix (_,(nbfix,_,_)) when nbfix <> 1 -> + compute_consteval_mutual_fix sigma env ref + | elim -> elim + +let reference_eval sigma env = function + | EvalConst cst as ref -> + (try + Cstmap.find cst !eval_table + with Not_found -> begin + let v = compute_consteval sigma env ref in + eval_table := Cstmap.add cst v !eval_table; + v + end) + | ref -> compute_consteval sigma env ref + +let rev_firstn_liftn fn ln = + let rec rfprec p res l = + if p = 0 then + res + else + match l with + | [] -> invalid_arg "Reduction.rev_firstn_liftn" + | a::rest -> rfprec (p-1) ((lift ln a)::res) rest + in + rfprec fn [] + +(* EliminationFix ([(yi1,Ti1);...;(yip,Tip)],n) means f is some + [y1:T1,...,yn:Tn](Fix(..) yi1 ... yip); + f is applied to largs and we need for recursive calls to build + [x1:Ti1',...,xp:Tip'](f a1..a(n-p) yi1 ... yip) + where a1...an are the n first arguments of largs and Tik' is Tik[yil=al] + To check ... *) + +let make_elim_fun (names,(nbfix,lv,n)) largs = + let labs = list_firstn n (list_of_stack largs) in + let p = List.length lv in + let ylv = List.map fst lv in + let la' = list_map_i + (fun q aq -> + try (mkRel (p+1-(list_index (n-q) ylv))) + with Not_found -> aq) 0 + (List.map (lift p) labs) + in + fun i -> + match names.(i) with + | None -> None + | Some ref -> Some ( +(* let fi = + if nbfix = 1 then + mkEvalRef ref + else + match ref with + | EvalConst (sp,args) -> + mkConst (make_path (dirpath sp) id (kind_of_path sp),args) + | _ -> anomaly "elimination of local fixpoints not implemented" + in +*) + list_fold_left_i + (fun i c (k,a) -> + mkLambda (Name(id_of_string"x"), + substl (rev_firstn_liftn (n-k) (-i) la') a, + c)) + 0 (applistc (mkEvalRef ref) la') lv) + +(* [f] is convertible to [Fix(recindices,bodynum),bodyvect)] make + the reduction using this extra information *) + +let contract_fix_use_function f + ((recindices,bodynum),(types,names,bodies as typedbodies)) = + let nbodies = Array.length recindices in + let make_Fi j = match f j with + | None -> mkFix((recindices,j),typedbodies) + | Some c -> c in +(* match List.nth names j with Name id -> f id | _ -> assert false in*) + let lbodies = list_tabulate make_Fi nbodies in + substl (List.rev lbodies) bodies.(bodynum) + +let reduce_fix_use_function f whfun fix stack = + match fix_recarg fix stack with + | None -> NotReducible + | Some (recargnum,recarg) -> + let (recarg'hd,_ as recarg') = + if isRel recarg then + (* The recarg cannot be a local def, no worry about the right env *) + (recarg, empty_stack) + else + whfun (recarg, empty_stack) in + let stack' = stack_assign stack recargnum (app_stack recarg') in + (match kind_of_term recarg'hd with + | Construct _ -> + Reduced (contract_fix_use_function f fix,stack') + | _ -> NotReducible) + +let contract_cofix_use_function f (bodynum,(_,names,bodies as typedbodies)) = + let nbodies = Array.length bodies in + let make_Fi j = match f j with + | None -> mkCoFix(j,typedbodies) + | Some c -> c in +(* match List.nth names j with Name id -> f id | _ -> assert false in*) + let subbodies = list_tabulate make_Fi nbodies in + substl subbodies bodies.(bodynum) + +let reduce_mind_case_use_function func env mia = + match kind_of_term mia.mconstr with + | Construct(ind_sp,i as cstr_sp) -> + let real_cargs = list_skipn mia.mci.ci_npar mia.mcargs in + applist (mia.mlf.(i-1), real_cargs) + | CoFix (_,(names,_,_) as cofix) -> + let build_fix_name i = + match names.(i) with + | Name id -> + if isConst func then + let (mp,dp,_) = repr_kn (destConst func) in + let kn = make_kn mp dp (label_of_id id) in + (match constant_opt_value env kn with + | None -> None + | Some _ -> Some (mkConst kn)) + else None + | Anonymous -> None in + let cofix_def = contract_cofix_use_function build_fix_name cofix in + mkCase (mia.mci, mia.mP, applist(cofix_def,mia.mcargs), mia.mlf) + | _ -> assert false + +let special_red_case sigma env whfun (ci, p, c, lf) = + let rec redrec s = + let (constr, cargs) = whfun s in + if isEvalRef env constr then + let ref = destEvalRef constr in + match reference_opt_value sigma env ref with + | None -> raise Redelimination + | Some gvalue -> + if reducible_mind_case gvalue then + reduce_mind_case_use_function constr env + {mP=p; mconstr=gvalue; mcargs=list_of_stack cargs; + mci=ci; mlf=lf} + else + redrec (gvalue, cargs) + else + if reducible_mind_case constr then + reduce_mind_case + {mP=p; mconstr=constr; mcargs=list_of_stack cargs; + mci=ci; mlf=lf} + else + raise Redelimination + in + redrec (c, empty_stack) + + +let rec red_elim_const env sigma ref largs = + match reference_eval sigma env ref with + | EliminationCases n when stack_args_size largs >= n -> + let c = reference_value sigma env ref in + let c', lrest = whd_betadelta_state env sigma (c,largs) in + (special_red_case sigma env (construct_const env sigma) (destCase c'), + lrest) + | EliminationFix (min,infos) when stack_args_size largs >=min -> + let c = reference_value sigma env ref in + let d, lrest = whd_betadelta_state env sigma (c,largs) in + let f = make_elim_fun ([|Some ref|],infos) largs in + let co = construct_const env sigma in + (match reduce_fix_use_function f co (destFix d) lrest with + | NotReducible -> raise Redelimination + | Reduced (c,rest) -> (nf_beta c, rest)) + | EliminationMutualFix (min,refgoal,refinfos) + when stack_args_size largs >= min -> + let rec descend ref args = + let c = reference_value sigma env ref in + if ref = refgoal then + (c,args) + else + let c', lrest = whd_betalet_state (c,args) in + descend (destEvalRef c') lrest in + let (_, midargs as s) = descend ref largs in + let d, lrest = whd_betadelta_state env sigma s in + let f = make_elim_fun refinfos midargs in + let co = construct_const env sigma in + (match reduce_fix_use_function f co (destFix d) lrest with + | NotReducible -> raise Redelimination + | Reduced (c,rest) -> (nf_beta c, rest)) + | _ -> raise Redelimination + +and construct_const env sigma = + let rec hnfstack (x, stack as s) = + match kind_of_term x with + | Cast (c,_) -> hnfstack (c, stack) + | App (f,cl) -> hnfstack (f, append_stack cl stack) + | Lambda (id,t,c) -> + (match decomp_stack stack with + | None -> assert false + | Some (c',rest) -> + stacklam hnfstack [c'] c rest) + | LetIn (n,b,t,c) -> stacklam hnfstack [b] c stack + | Case (ci,p,c,lf) -> + hnfstack + (special_red_case sigma env + (construct_const env sigma) (ci,p,c,lf), stack) + | Construct _ -> s + | CoFix _ -> s + | Fix fix -> + (match reduce_fix hnfstack fix stack with + | Reduced s' -> hnfstack s' + | NotReducible -> raise Redelimination) + | _ when isEvalRef env x -> + let ref = destEvalRef x in + (try + hnfstack (red_elim_const env sigma ref stack) + with Redelimination -> + (match reference_opt_value sigma env ref with + | Some cval -> + (match kind_of_term cval with + | CoFix _ -> s + | _ -> hnfstack (cval, stack)) + | None -> + raise Redelimination)) + | _ -> raise Redelimination + in + hnfstack + +(************************************************************************) +(* Special Purpose Reduction Strategies *) + +(* Red reduction tactic: reduction to a product *) + +let internal_red_product env sigma c = + let simpfun = clos_norm_flags betaiotazeta env sigma in + let rec redrec env x = + match kind_of_term x with + | App (f,l) -> + (match kind_of_term f with + | Fix fix -> + let stack = append_stack l empty_stack in + (match fix_recarg fix stack with + | None -> raise Redelimination + | Some (recargnum,recarg) -> + let recarg' = redrec env recarg in + let stack' = stack_assign stack recargnum recarg' in + simpfun (app_stack (f,stack'))) + | _ -> simpfun (appvect (redrec env f, l))) + | Cast (c,_) -> redrec env c + | Prod (x,a,b) -> mkProd (x, a, redrec (push_rel (x,None,a) env) b) + | LetIn (x,a,b,t) -> redrec env (subst1 a t) + | Case (ci,p,d,lf) -> simpfun (mkCase (ci,p,redrec env d,lf)) + | _ when isEvalRef env x -> + (* TO DO: re-fold fixpoints after expansion *) + (* to get true one-step reductions *) + let ref = destEvalRef x in + (match reference_opt_value sigma env ref with + | None -> raise Redelimination + | Some c -> c) + | _ -> raise Redelimination + in redrec env c + +let red_product env sigma c = + try internal_red_product env sigma c + with Redelimination -> error "Not reducible" + +(* Hnf reduction tactic: *) + +let hnf_constr env sigma c = + let rec redrec (x, largs as s) = + match kind_of_term x with + | Lambda (n,t,c) -> + (match decomp_stack largs with + | None -> app_stack s + | Some (a,rest) -> + stacklam redrec [a] c rest) + | LetIn (n,b,t,c) -> stacklam redrec [b] c largs + | App (f,cl) -> redrec (f, append_stack cl largs) + | Cast (c,_) -> redrec (c, largs) + | Case (ci,p,c,lf) -> + (try + redrec + (special_red_case sigma env (whd_betadeltaiota_state env sigma) + (ci, p, c, lf), largs) + with Redelimination -> + app_stack s) + | Fix fix -> + (match reduce_fix (whd_betadeltaiota_state env sigma) fix largs with + | Reduced s' -> redrec s' + | NotReducible -> app_stack s) + | _ when isEvalRef env x -> + let ref = destEvalRef x in + (try + let (c',lrest) = red_elim_const env sigma ref largs in + redrec (c', lrest) + with Redelimination -> + match reference_opt_value sigma env ref with + | Some c -> + (match kind_of_term (snd (decompose_lam c)) with + | CoFix _ | Fix _ -> app_stack (x,largs) + | _ -> redrec (c, largs)) + | None -> app_stack s) + | _ -> app_stack s + in + redrec (c, empty_stack) + +(* Simpl reduction tactic: same as simplify, but also reduces + elimination constants *) + +let whd_nf env sigma c = + let rec nf_app (c, stack as s) = + match kind_of_term c with + | Lambda (name,c1,c2) -> + (match decomp_stack stack with + | None -> (c,empty_stack) + | Some (a1,rest) -> + stacklam nf_app [a1] c2 rest) + | LetIn (n,b,t,c) -> stacklam nf_app [b] c stack + | App (f,cl) -> nf_app (f, append_stack cl stack) + | Cast (c,_) -> nf_app (c, stack) + | Case (ci,p,d,lf) -> + (try + nf_app (special_red_case sigma env nf_app (ci,p,d,lf), stack) + with Redelimination -> + s) + | Fix fix -> + (match reduce_fix nf_app fix stack with + | Reduced s' -> nf_app s' + | NotReducible -> s) + | _ when isEvalRef env c -> + (try + nf_app (red_elim_const env sigma (destEvalRef c) stack) + with Redelimination -> + s) + | _ -> s + in + app_stack (nf_app (c, empty_stack)) + +let nf env sigma c = strong whd_nf env sigma c + +let is_reference c = + try let r = reference_of_constr c in true with _ -> false + +let is_head c t = + match kind_of_term t with + | App (f,_) -> f = c + | _ -> false + +let contextually byhead (locs,c) f env sigma t = + let maxocc = List.fold_right max locs 0 in + let pos = ref 1 in + let check = ref true in + let except = List.exists (fun n -> n<0) locs in + if except & (List.exists (fun n -> n>=0) locs) + then error "mixing of positive and negative occurences" + else + let rec traverse (env,c as envc) t = + if locs <> [] & (not except) & (!pos > maxocc) then t + else + if (not byhead & eq_constr c t) or (byhead & is_head c t) then + let ok = + if except then not (List.mem (- !pos) locs) + else (locs = [] or List.mem !pos locs) in + incr pos; + if ok then + f env sigma t + else if byhead then + (* find other occurrences of c in t; TODO: ensure left-to-right *) + let (f,l) = destApplication t in + mkApp (f, array_map_left (traverse envc) l) + else + t + else + map_constr_with_binders_left_to_right + (fun d (env,c) -> (push_rel d env,lift 1 c)) + traverse envc t + in + let t' = traverse (env,c) t in + if locs <> [] & List.exists (fun o -> o >= !pos or o <= - !pos) locs then + errorlabstrm "contextually" (str "Too few occurences"); + t' + +(* linear bindings (following pretty-printer) of the value of name in c. + * n is the number of the next occurence of name. + * ol is the occurence list to find. *) +let rec substlin env name n ol c = + match kind_of_term c with + | Const kn when EvalConstRef kn = name -> + if List.hd ol = n then + try + (n+1, List.tl ol, constant_value env kn) + with + NotEvaluableConst _ -> + errorlabstrm "substlin" + (pr_kn kn ++ str " is not a defined constant") + else + ((n+1), ol, c) + + | Var id when EvalVarRef id = name -> + if List.hd ol = n then + match lookup_named id env with + | (_,Some c,_) -> (n+1, List.tl ol, c) + | _ -> + errorlabstrm "substlin" + (pr_id id ++ str " is not a defined constant") + else + ((n+1), ol, c) + + (* INEFFICIENT: OPTIMIZE *) + | App (c1,cl) -> + Array.fold_left + (fun (n1,ol1,c1') c2 -> + (match ol1 with + | [] -> (n1,[],applist(c1',[c2])) + | _ -> + let (n2,ol2,c2') = substlin env name n1 ol1 c2 in + (n2,ol2,applist(c1',[c2'])))) + (substlin env name n ol c1) cl + + | Lambda (na,c1,c2) -> + let (n1,ol1,c1') = substlin env name n ol c1 in + (match ol1 with + | [] -> (n1,[],mkLambda (na,c1',c2)) + | _ -> + let (n2,ol2,c2') = substlin env name n1 ol1 c2 in + (n2,ol2,mkLambda (na,c1',c2'))) + + | LetIn (na,c1,t,c2) -> + let (n1,ol1,c1') = substlin env name n ol c1 in + (match ol1 with + | [] -> (n1,[],mkLetIn (na,c1',t,c2)) + | _ -> + let (n2,ol2,c2') = substlin env name n1 ol1 c2 in + (n2,ol2,mkLetIn (na,c1',t,c2'))) + + | Prod (na,c1,c2) -> + let (n1,ol1,c1') = substlin env name n ol c1 in + (match ol1 with + | [] -> (n1,[],mkProd (na,c1',c2)) + | _ -> + let (n2,ol2,c2') = substlin env name n1 ol1 c2 in + (n2,ol2,mkProd (na,c1',c2'))) + + | Case (ci,p,d,llf) -> + let rec substlist nn oll = function + | [] -> (nn,oll,[]) + | f::lfe -> + let (nn1,oll1,f') = substlin env name nn oll f in + (match oll1 with + | [] -> (nn1,[],f'::lfe) + | _ -> + let (nn2,oll2,lfe') = substlist nn1 oll1 lfe in + (nn2,oll2,f'::lfe')) + in + let (n1,ol1,p') = substlin env name n ol p in (* ATTENTION ERREUR *) + (match ol1 with (* si P pas affiche *) + | [] -> (n1,[],mkCase (ci, p', d, llf)) + | _ -> + let (n2,ol2,d') = substlin env name n1 ol1 d in + (match ol2 with + | [] -> (n2,[],mkCase (ci, p', d', llf)) + | _ -> + let (n3,ol3,lf') = substlist n2 ol2 (Array.to_list llf) + in (n3,ol3,mkCase (ci, p', d', Array.of_list lf')))) + + | Cast (c1,c2) -> + let (n1,ol1,c1') = substlin env name n ol c1 in + (match ol1 with + | [] -> (n1,[],mkCast (c1',c2)) + | _ -> + let (n2,ol2,c2') = substlin env name n1 ol1 c2 in + (n2,ol2,mkCast (c1',c2'))) + + | Fix _ -> + (warning "do not consider occurrences inside fixpoints"; (n,ol,c)) + + | CoFix _ -> + (warning "do not consider occurrences inside cofixpoints"; (n,ol,c)) + + | (Rel _|Meta _|Var _|Sort _ + |Evar _|Const _|Ind _|Construct _) -> (n,ol,c) + +let string_of_evaluable_ref env = function + | EvalVarRef id -> string_of_id id + | EvalConstRef kn -> + string_of_qualid + (Nametab.shortest_qualid_of_global (vars_of_env env) (ConstRef kn)) + +let unfold env sigma name = + if is_evaluable env name then + clos_norm_flags (unfold_red name) env sigma + else + error (string_of_evaluable_ref env name^" is opaque") + +(* [unfoldoccs : (readable_constraints -> (int list * section_path) -> constr -> constr)] + * Unfolds the constant name in a term c following a list of occurrences occl. + * at the occurrences of occ_list. If occ_list is empty, unfold all occurences. + * Performs a betaiota reduction after unfolding. *) +let unfoldoccs env sigma (occl,name) c = + match occl with + | [] -> unfold env sigma name c + | l -> + match substlin env name 1 (Sort.list (<) l) c with + | (_,[],uc) -> nf_betaiota uc + | (1,_,_) -> + error ((string_of_evaluable_ref env name)^" does not occur") + | _ -> error ("bad occurrence numbers of " + ^(string_of_evaluable_ref env name)) + +(* Unfold reduction tactic: *) +let unfoldn loccname env sigma c = + List.fold_left (fun c occname -> unfoldoccs env sigma occname c) c loccname + +(* Re-folding constants tactics: refold com in term c *) +let fold_one_com com env sigma c = + let rcom = + try red_product env sigma com + with Redelimination -> error "Not reducible" in + subst1 com (subst_term rcom c) + +let fold_commands cl env sigma c = + List.fold_right (fun com -> fold_one_com com env sigma) (List.rev cl) c + + +(* call by value reduction functions *) +let cbv_norm_flags flags env sigma t = + cbv_norm (create_cbv_infos flags env) (nf_evar sigma t) + +let cbv_beta = cbv_norm_flags beta empty_env Evd.empty +let cbv_betaiota = cbv_norm_flags betaiota empty_env Evd.empty +let cbv_betadeltaiota env sigma = cbv_norm_flags betadeltaiota env sigma + +let compute = cbv_betadeltaiota + +(* Pattern *) + +(* gives [na:ta]c' such that c converts to ([na:ta]c' a), abstracting only + * the specified occurrences. *) + +let abstract_scheme env sigma (locc,a) t = + let ta = Retyping.get_type_of env sigma a in + let na = named_hd env ta Anonymous in + if occur_meta ta then error "cannot find a type for the generalisation"; + if occur_meta a then + mkLambda (na,ta,t) + else + mkLambda (na, ta,subst_term_occ locc a t) + + +let pattern_occs loccs_trm env sigma c = + let abstr_trm = List.fold_right (abstract_scheme env sigma) loccs_trm c in + applist(abstr_trm, List.map snd loccs_trm) + +(* Generic reduction: reduction functions used in reduction tactics *) + +type red_expr = (constr, evaluable_global_reference) red_expr_gen + +open RedFlags + +let make_flag_constant = function + | EvalVarRef id -> fVAR id + | EvalConstRef sp -> fCONST sp + +let make_flag f = + let red = no_red in + let red = if f.rBeta then red_add red fBETA else red in + let red = if f.rIota then red_add red fIOTA else red in + let red = if f.rZeta then red_add red fZETA else red in + let red = + if f.rDelta then (* All but rConst *) + let red = red_add red fDELTA in + let red = red_add_transparent red (Conv_oracle.freeze ()) in + List.fold_right + (fun v red -> red_sub red (make_flag_constant v)) + f.rConst red + else (* Only rConst *) + let red = red_add_transparent (red_add red fDELTA) all_opaque in + List.fold_right + (fun v red -> red_add red (make_flag_constant v)) + f.rConst red + in red + +let red_expr_tab = ref Stringmap.empty + +let declare_red_expr s f = + try + let _ = Stringmap.find s !red_expr_tab in + error ("There is already a reduction expression of name "^s) + with Not_found -> + red_expr_tab := Stringmap.add s f !red_expr_tab + +let reduction_of_redexp = function + | Red internal -> if internal then internal_red_product else red_product + | Hnf -> hnf_constr + | Simpl (Some (_,c as lp)) -> contextually (is_reference c) lp nf + | Simpl None -> nf + | Cbv f -> cbv_norm_flags (make_flag f) + | Lazy f -> clos_norm_flags (make_flag f) + | Unfold ubinds -> unfoldn ubinds + | Fold cl -> fold_commands cl + | Pattern lp -> pattern_occs lp + | ExtraRedExpr (s,c) -> + (try Stringmap.find s !red_expr_tab + with Not_found -> error("unknown user-defined reduction \""^s^"\"")) +(* Used in several tactics. *) + +exception NotStepReducible + +let one_step_reduce env sigma c = + let rec redrec (x, largs as s) = + match kind_of_term x with + | Lambda (n,t,c) -> + (match decomp_stack largs with + | None -> raise NotStepReducible + | Some (a,rest) -> (subst1 a c, rest)) + | App (f,cl) -> redrec (f, append_stack cl largs) + | LetIn (_,f,_,cl) -> (subst1 f cl,largs) + | Case (ci,p,c,lf) -> + (try + (special_red_case sigma env (whd_betadeltaiota_state env sigma) + (ci,p,c,lf), largs) + with Redelimination -> raise NotStepReducible) + | Fix fix -> + (match reduce_fix (whd_betadeltaiota_state env sigma) fix largs with + | Reduced s' -> s' + | NotReducible -> raise NotStepReducible) + | Cast (c,_) -> redrec (c,largs) + | _ when isEvalRef env x -> + let ref = + try destEvalRef x + with Redelimination -> raise NotStepReducible in + (try + red_elim_const env sigma ref largs + with Redelimination -> + match reference_opt_value sigma env ref with + | Some d -> d, largs + | None -> raise NotStepReducible) + + | _ -> raise NotStepReducible + in + app_stack (redrec (c, empty_stack)) + +(* put t as t'=(x1:A1)..(xn:An)B with B an inductive definition of name name + return name, B and t' *) + +let reduce_to_ind_gen allow_product env sigma t = + let rec elimrec env t l = + let c, _ = Reductionops.whd_stack t in + match kind_of_term c with + | Ind (mind,args) -> ((mind,args),it_mkProd_or_LetIn t l) + | Prod (n,ty,t') -> + if allow_product then + elimrec (push_rel (n,None,t) env) t' ((n,None,ty)::l) + else + errorlabstrm "tactics__reduce_to_mind" + (str"Not an inductive definition") + | _ -> + (try + let t' = nf_betaiota (one_step_reduce env sigma t) in + elimrec env t' l + with NotStepReducible -> + errorlabstrm "tactics__reduce_to_mind" + (str"Not an inductive product")) + in + elimrec env t [] + +let reduce_to_quantified_ind x = reduce_to_ind_gen true x +let reduce_to_atomic_ind x = reduce_to_ind_gen false x + +let reduce_to_ref_gen allow_product env sigma ref t = + let rec elimrec env t l = + let c, _ = Reductionops.whd_stack t in + match kind_of_term c with + | Prod (n,ty,t') -> + if allow_product then + elimrec (push_rel (n,None,t) env) t' ((n,None,ty)::l) + else + errorlabstrm "Tactics.reduce_to_ref_gen" + (str"Not an induction object of atomic type") + | _ -> + try + if reference_of_constr c = ref + then it_mkProd_or_LetIn t l + else raise Not_found + with Not_found -> + try + let t' = nf_betaiota (one_step_reduce env sigma t) in + elimrec env t' l + with NotStepReducible -> raise Not_found + in + elimrec env t [] + +let reduce_to_quantified_ref = reduce_to_ref_gen true +let reduce_to_atomic_ref = reduce_to_ref_gen false -- cgit v1.2.3