diff options
author | herbelin <herbelin@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2000-09-10 07:19:28 +0000 |
---|---|---|
committer | herbelin <herbelin@85f007b7-540e-0410-9357-904b9bb8a0f7> | 2000-09-10 07:19:28 +0000 |
commit | 79dc33cbc403ebab0bd1fe815c13f740f0a1b850 (patch) | |
tree | e38e167003d7dd97d95a59ea7c026a1629b346f8 /kernel | |
parent | c0ff579606f2eba24bc834316d8bb7bcc076000d (diff) |
Ajout d'un LetIn primitif.
Abstraction de constr via kind_of_constr dans une bonne partie du code.
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@591 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/abstraction.ml | 2 | ||||
-rw-r--r-- | kernel/closure.ml | 366 | ||||
-rw-r--r-- | kernel/closure.mli | 78 | ||||
-rw-r--r-- | kernel/declarations.ml | 2 | ||||
-rw-r--r-- | kernel/environ.ml | 51 | ||||
-rw-r--r-- | kernel/environ.mli | 1 | ||||
-rw-r--r-- | kernel/indtypes.ml | 93 | ||||
-rw-r--r-- | kernel/inductive.ml | 2 | ||||
-rw-r--r-- | kernel/instantiate.ml | 2 | ||||
-rw-r--r-- | kernel/reduction.ml | 716 | ||||
-rw-r--r-- | kernel/reduction.mli | 20 | ||||
-rw-r--r-- | kernel/safe_typing.ml | 12 | ||||
-rw-r--r-- | kernel/sign.ml | 51 | ||||
-rw-r--r-- | kernel/sign.mli | 2 | ||||
-rw-r--r-- | kernel/sosub.ml | 34 | ||||
-rw-r--r-- | kernel/sosub.mli | 2 | ||||
-rw-r--r-- | kernel/term.ml | 1193 | ||||
-rw-r--r-- | kernel/term.mli | 192 | ||||
-rw-r--r-- | kernel/type_errors.ml | 24 | ||||
-rw-r--r-- | kernel/type_errors.mli | 25 | ||||
-rw-r--r-- | kernel/typeops.ml | 338 |
21 files changed, 1860 insertions, 1346 deletions
diff --git a/kernel/abstraction.ml b/kernel/abstraction.ml index 9df751b46..a6e5937a4 100644 --- a/kernel/abstraction.ml +++ b/kernel/abstraction.ml @@ -3,7 +3,7 @@ open Util open Names -open Generic +(*i open Generic i*) open Term type abstraction_body = { diff --git a/kernel/closure.ml b/kernel/closure.ml index f452a6dfc..948361690 100644 --- a/kernel/closure.ml +++ b/kernel/closure.ml @@ -4,7 +4,6 @@ open Util open Pp open Term -open Generic open Names open Environ open Instantiate @@ -31,6 +30,9 @@ let stop() = (* sets of reduction kinds *) type red_kind = BETA | DELTA of sorts oper | IOTA +(* Hack: we use oper (Const "$LOCAL VAR$") for local variables *) +let local_const_oper = Const (make_path [] (id_of_string "$LOCAL VAR$") CCI) + type reds = { r_beta : bool; r_delta : sorts oper -> bool; (* this is unsafe: exceptions may pop out *) @@ -157,6 +159,58 @@ let infos_under infos = i_tab = infos.i_tab } +(* explicit substitutions of type 'a *) +type 'a subs = + | ESID (* ESID = identity *) + | CONS of 'a * 'a subs (* CONS(t,S) = (S.t) parallel substitution *) + | SHIFT of int * 'a subs (* SHIFT(n,S) = (^n o S) terms in S are relocated *) + (* with n vars *) + | LIFT of int * 'a subs (* LIFT(n,S) = (%n S) stands for ((^n o S).n...1) *) + +(* operations of subs: collapses constructors when possible. + * Needn't be recursive if we always use these functions + *) + +let subs_cons(x,s) = CONS(x,s) + +let subs_liftn n = function + | ESID -> ESID (* the identity lifted is still the identity *) + (* (because (^1.1) --> id) *) + | LIFT (p,lenv) -> LIFT (p+n, lenv) + | lenv -> LIFT (n,lenv) + +let subs_lift a = subs_liftn 1 a + +let subs_shft = function + | (0, s) -> s + | (n, SHIFT (k,s1)) -> SHIFT (k+n, s1) + | (n, s) -> SHIFT (n,s) + +(* Expands de Bruijn k in the explicit substitution subs + * lams accumulates de shifts to perform when retrieving the i-th value + * the rules used are the following: + * + * [id]k --> k + * [S.t]1 --> t + * [S.t]k --> [S](k-1) if k > 1 + * [^n o S] k --> [^n]([S]k) + * [(%n S)] k --> k if k <= n + * [(%n S)] k --> [^n]([S](k-n)) + * + * the result is (Inr k) when the variable is just relocated + *) +let rec exp_rel lams k subs = + match (k,subs) with + | (1, CONS (def,_)) -> Inl(lams,def) + | (_, CONS (_,l)) -> exp_rel lams (pred k) l + | (_, LIFT (n,_)) when k<=n -> Inr(lams+k) + | (_, LIFT (n,l)) -> exp_rel (n+lams) (k-n) l + | (_, SHIFT (n,s)) -> exp_rel (n+lams) k s + | (_, ESID) -> Inr(lams+k) + +let expand_rel k subs = exp_rel 0 k subs + + (**** Call by value reduction ****) (* The type of terms with closure. The meaning of the constructors and @@ -185,7 +239,8 @@ let infos_under infos = type cbv_value = | VAL of int * constr | LAM of name * constr * constr * cbv_value subs - | FIXP of sorts oper * constr array * cbv_value subs * cbv_value list + | FIXP of fixpoint * cbv_value subs * cbv_value list + | COFIXP of cofixpoint * cbv_value subs * cbv_value list | CONSTR of int * (section_path * int) * cbv_value array * cbv_value list (* les vars pourraient etre des constr, @@ -197,8 +252,10 @@ type cbv_value = let rec shift_value n = function | VAL (k,v) -> VAL ((k+n),v) | LAM (x,a,b,s) -> LAM (x,a,b,subs_shft (n,s)) - | FIXP (op,bv,s,args) -> - FIXP (op,bv,subs_shft (n,s), List.map (shift_value n) args) + | FIXP (fix,s,args) -> + FIXP (fix,subs_shft (n,s), List.map (shift_value n) args) + | COFIXP (cofix,s,args) -> + COFIXP (cofix,subs_shft (n,s), List.map (shift_value n) args) | CONSTR (i,spi,vars,args) -> CONSTR (i, spi, Array.map (shift_value n) vars, List.map (shift_value n) args) @@ -210,20 +267,23 @@ let rec shift_value n = function * (S, (fix Fi {F0 := T0 .. Fn-1 := Tn-1})) * -> (S. [S]F0 . [S]F1 ... . [S]Fn-1, Ti) *) -let contract_fixp env fix = - let (bnum, bodies, make_body) = match fix with - | DOPN(Fix(reci,i),bvect) -> - (i, array_last bvect, (fun j -> FIXP(Fix(reci,j), bvect, env, []))) - | DOPN(CoFix i,bvect) -> - (i, array_last bvect, (fun j -> FIXP(CoFix j, bvect, env, []))) - | _ -> anomaly "Closure.contract_fixp: not a (co)fixpoint" - in - let rec subst_bodies_from_i i subs = function - | DLAM(_,t) -> subst_bodies_from_i (i+1) (subs_cons (make_body i, subs)) t - | DLAMV(_,bds) -> (subs_cons (make_body i, subs), bds.(bnum)) - | _ -> anomaly "Closure.contract_fixp: malformed (co)fixpoint" +let contract_fixp env ((reci,i),(_,_,bds as bodies)) = + let make_body j = FIXP(((reci,j),bodies), env, []) in + let n = Array.length bds in + let rec subst_bodies_from_i i subs = + if i=n then subs + else subst_bodies_from_i (i+1) (subs_cons (make_body i, subs)) + in + subst_bodies_from_i 0 env, bds.(i) + +let contract_cofixp env (i,(_,_,bds as bodies)) = + let make_body j = COFIXP((j,bodies), env, []) in + let n = Array.length bds in + let rec subst_bodies_from_i i subs = + if i=n then subs + else subst_bodies_from_i (i+1) (subs_cons (make_body i, subs)) in - subst_bodies_from_i 0 env bodies + subst_bodies_from_i 0 env, bds.(i) (* type of terms with a hole. This hole can appear only under AppL or Case. @@ -274,12 +334,13 @@ let red_allowed flags stack rk = *) let strip_appl head stack = match head with - | FIXP (op,bv,env,app) -> (FIXP(op,bv,env,[]), stack_app app stack) + | FIXP (fix,env,app) -> (FIXP(fix,env,[]), stack_app app stack) + | COFIXP (cofix,env,app) -> (COFIXP(cofix,env,[]), stack_app app stack) | CONSTR (i,spi,vars,app) -> (CONSTR(i,spi,vars,[]), stack_app app stack) | _ -> (head, stack) -(* Invariant: if the result of norm_head is CONSTR or FIXP, it last +(* Invariant: if the result of norm_head is CONSTR or (CO)FIXP, it last * argument is []. * Because we must put all the applied terms in the stack. *) @@ -298,12 +359,18 @@ let rec check_app_constr redfun = function | _ -> false) | (_::l, n) -> check_app_constr redfun (l,(pred n)) -let fixp_reducible redfun flgs op stk = +let fixp_reducible redfun flgs ((reci,i),_) stk = + if red_allowed flgs stk IOTA then + match stk with (* !!! for Acc_rec: reci.(i) = -2 *) + | APP(appl,_) -> reci.(i) >=0 & check_app_constr redfun (appl, reci.(i)) + | _ -> false + else + false + +let cofixp_reducible redfun flgs _ stk = if red_allowed flgs stk IOTA then - match (op,stk) with (* !!! for Acc_rec: reci.(i) = -2 *) - | (Fix (reci,i), APP(appl,_)) -> - (reci.(i) >= 0 & check_app_constr redfun (appl, reci.(i))) - | (CoFix i, (CASE _ | APP(_,CASE _))) -> true + match stk with + | (CASE _ | APP(_,CASE _)) -> true | _ -> false else false @@ -318,65 +385,72 @@ let mindsp_nparams env sp = * constructor, a lambda or a fixp in the head. If not, it is a value * and is completely computed here. The head redexes are NOT reduced: * the function returns the pair of a cbv_value and its stack. * - * Invariant: if the result of norm_head is CONSTR or FIXP, it last + * Invariant: if the result of norm_head is CONSTR or (CO)FIXP, it last * argument is []. Because we must put all the applied terms in the * stack. *) let rec norm_head info env t stack = (* no reduction under binders *) - match t with + match kind_of_term t with (* stack grows (remove casts) *) - | DOPN (AppL,appl) -> (* Applied terms are normalized immediately; + | IsAppL (head,args) -> (* Applied terms are normalized immediately; they could be computed when getting out of the stack *) - (match Array.to_list appl with - | head::args -> - let nargs = List.map (cbv_stack_term info TOP env) args in - norm_head info env head (stack_app nargs stack) - | [] -> anomaly "norm_head : malformed constr AppL [||]") - | DOPN (MutCase _,_) -> - let (ci,p,c,v) = destCase t in - norm_head info env c (CASE(p,v,ci,env,stack)) - | DOP2 (Cast,ct,c) -> norm_head info env ct stack + let nargs = List.map (cbv_stack_term info TOP env) args in + norm_head info env head (stack_app nargs stack) + | IsMutCase (ci,p,c,v) -> norm_head info env c (CASE(p,v,ci,env,stack)) + | IsCast (ct,_) -> norm_head info env ct stack (* constants, axioms * the first pattern is CRUCIAL, n=0 happens very often: * when reducing closed terms, n is always 0 *) - | Rel i -> (match expand_rel i env with + | IsRel i -> (match expand_rel i env with | Inl (0,v) -> reduce_const_body (cbv_norm_more info) v stack | Inl (n,v) -> reduce_const_body (cbv_norm_more info) (shift_value n v) stack | Inr n -> (VAL(0, Rel n), stack)) - | DOPN ((Const _ | Evar _ | Abst _) as op, vars) - when red_allowed info.i_flags stack (DELTA op) -> - let normt = DOPN(op, Array.map (cbv_norm_term info env) vars) in - (match const_value_cache info normt with - | Some body -> reduce_const_body (cbv_norm_more info) body stack - | None -> (VAL(0,normt), stack)) + | IsConst (sp,vars) -> + let normt = mkConst (sp,Array.map (cbv_norm_term info env) vars) in + if red_allowed info.i_flags stack (DELTA (Const sp)) then + match const_value_cache info normt with + | Some body -> reduce_const_body (cbv_norm_more info) body stack + | None -> (VAL(0,normt), stack) + else (VAL(0,normt), stack) + | IsLetIn (x, b, t, c) -> + if red_allowed info.i_flags stack (DELTA local_const_oper) then + let b = cbv_stack_term info TOP env b in + norm_head info (subs_cons (b,env)) c stack + else + let normt = + mkLetIn (x, cbv_norm_term info env b, + cbv_norm_term info env t, + cbv_norm_term info (subs_lift env) c) in + (VAL(0,normt), stack) (* Considérer une coupure commutative ? *) + | IsEvar (n,vars) -> + let normt = mkEvar (n,Array.map (cbv_norm_term info env) vars) in + if red_allowed info.i_flags stack (DELTA (Evar n)) then + match const_value_cache info normt with + | Some body -> reduce_const_body (cbv_norm_more info) body stack + | None -> (VAL(0,normt), stack) + else (VAL(0,normt), stack) (* non-neutral cases *) - | DOP2 (Lambda,a,DLAM(x,b)) -> (LAM(x,a,b,env), stack) - | DOPN ((Fix _ | CoFix _) as op, v) -> (FIXP(op,v,env,[]), stack) - | DOPN (MutConstruct(spi,i),vars) -> + | IsLambda (x,a,b) -> (LAM(x,a,b,env), stack) + | IsFix fix -> (FIXP(fix,env,[]), stack) + | IsCoFix cofix -> (COFIXP(cofix,env,[]), stack) + | IsMutConstruct ((spi,i),vars) -> (CONSTR(i,spi, Array.map (cbv_stack_term info TOP env) vars,[]), stack) (* neutral cases *) - | (VAR _ | DOP0 _) -> (VAL(0, t), stack) - | DOP1 (op, nt) -> (VAL(0, DOP1(op, cbv_norm_term info env nt)), stack) - | DOP2 (op,a,b) -> - (VAL(0, DOP2(op, cbv_norm_term info env a, cbv_norm_term info env b)), - stack) - | DOPN (op,vars) -> - (VAL(0, DOPN(op, Array.map (cbv_norm_term info env) vars)), stack) - | DOPL (op,l) -> - (VAL(0, DOPL(op, List.map (cbv_norm_term info env) l)), stack) - | DLAM (x,t) -> - (VAL(0, DLAM(x, cbv_norm_term info (subs_lift env) t)), stack) - | DLAMV (x,ve) -> - (VAL(0, DLAMV(x, Array.map(cbv_norm_term info (subs_lift env)) ve)), - stack) - + | (IsVar _ | IsSort _ | IsMeta _ | IsXtra _ ) -> (VAL(0, t), stack) + | IsMutInd (sp,vars) -> + (VAL(0, mkMutInd (sp, Array.map (cbv_norm_term info env) vars)), stack) + | IsProd (x,t,c) -> + (VAL(0, mkProd (x, cbv_norm_term info env t, + cbv_norm_term info (subs_lift env) c)), + stack) + | IsAbst (_,_) -> failwith "No longer implemented" (* cbv_stack_term performs weak reduction on constr t under the subs * env, with context stack, i.e. ([env]t stack). First computes weak @@ -392,12 +466,17 @@ and cbv_stack_term info stack env t = let subs = subs_cons (arg,env) in cbv_stack_term info (stack_app args stk) subs b - (* a Fix applied enough, - constructor guard satisfied or Cofix in a Case -> IOTA *) - | (FIXP(op,bv,env,_), stk) - when fixp_reducible (cbv_norm_more info) info.i_flags op stk -> - let (envf,redfix) = contract_fixp env (DOPN(op,bv)) in - cbv_stack_term info stk envf redfix + (* a Fix applied enough -> IOTA *) + | (FIXP(fix,env,_), stk) + when fixp_reducible (cbv_norm_more info) info.i_flags fix stk -> + let (envf,redfix) = contract_fixp env fix in + cbv_stack_term info stk envf redfix + + (* constructor guard satisfied or Cofix in a Case -> IOTA *) + | (COFIXP(cofix,env,_), stk) + when cofixp_reducible (cbv_norm_more info) info.i_flags cofix stk -> + let (envf,redfix) = contract_cofixp env cofix in + cbv_stack_term info stk envf redfix (* constructor in a Case -> IOTA (use red_under because we know there is a Case) *) @@ -414,7 +493,8 @@ and cbv_stack_term info stack env t = (* may be reduced later by application *) | (head, TOP) -> head - | (FIXP(op,bv,env,_), APP(appl,TOP)) -> FIXP(op,bv,env,appl) + | (FIXP(fix,env,_), APP(appl,TOP)) -> FIXP(fix,env,appl) + | (COFIXP(cofix,env,_), APP(appl,TOP)) -> COFIXP(cofix,env,appl) | (CONSTR(n,spi,vars,_), APP(appl,TOP)) -> CONSTR(n,spi,vars,appl) (* definitely a value *) @@ -452,19 +532,28 @@ and cbv_norm_term info env t = (* reduction of a cbv_value to a constr *) and cbv_norm_value info = function (* reduction under binders *) | VAL (n,v) -> lift n v - | LAM (x,a,b,env) -> DOP2(Lambda, cbv_norm_term info env a, - DLAM(x,cbv_norm_term info (subs_lift env) b)) - | FIXP (op,cl,env,args) -> + | LAM (x,a,b,env) -> + mkLambda (x, cbv_norm_term info env a, + cbv_norm_term info (subs_lift env) b) + | FIXP ((lij,(lty,lna,bds)),env,args) -> + applistc + (mkFix (lij, + (Array.map (cbv_norm_term info env) lty, lna, + Array.map (cbv_norm_term info + (subs_liftn (Array.length lty) env)) bds))) + (List.map (cbv_norm_value info) args) + | COFIXP ((j,(lty,lna,bds)),env,args) -> applistc - (DOPN(op, Array.map (cbv_norm_term info env) cl)) + (mkCoFix (j, + (Array.map (cbv_norm_term info env) lty, lna, + Array.map (cbv_norm_term info + (subs_liftn (Array.length lty) env)) bds))) (List.map (cbv_norm_value info) args) | CONSTR (n,spi,vars,args) -> applistc - (DOPN (MutConstruct(spi,n), Array.map (cbv_norm_value info) vars)) + (mkMutConstruct ((spi,n), Array.map (cbv_norm_value info) vars)) (List.map (cbv_norm_value info) args) - - type 'a cbv_infos = (cbv_value, 'a) infos (* constant bodies are normalized at the first expansion *) @@ -499,22 +588,40 @@ let cbv_norm infos constr = * substitution applied to a constr *) -type 'oper freeze = { +type freeze = { mutable norm: bool; - mutable term: 'oper frterm } + mutable term: frterm } -and 'oper frterm = +and frterm = | FRel of int | FVAR of identifier - | FOP0 of 'oper - | FOP1 of 'oper * 'oper freeze - | FOP2 of 'oper * 'oper freeze * 'oper freeze - | FOPN of 'oper * 'oper freeze array - | FOPL of 'oper * 'oper freeze list - | FLAM of name * 'oper freeze * 'oper term * 'oper freeze subs - | FLAMV of name * 'oper freeze array * 'oper term array * 'oper freeze subs - | FLIFT of int * 'oper freeze - | FFROZEN of 'oper term * 'oper freeze subs + | FOP0 of sorts oper + | FOP1 of sorts oper * freeze + | FOP2 of sorts oper * freeze * freeze + | FOPN of sorts oper * freeze array + | FLAM of name * freeze * constr * freeze subs + | FLAMV of name * freeze array * constr array * freeze subs + | FLam of name * type_freeze * freeze * constr * freeze subs + | FPrd of name * type_freeze * freeze * constr * freeze subs + | FLet of name * freeze * type_freeze * freeze * constr * freeze subs + | FLIFT of int * freeze + | FFROZEN of constr * freeze subs + +(* Cas où typed_type est casté en interne +and type_freeze = freeze * sorts + *) +(* Cas où typed_type n'est pas casté *) +and type_freeze = freeze +(**) + +(* +let typed_map f t = f (body_of_type t), level_of_type t +let typed_unmap f (t,s) = make_typed (f t) s +*) +(**) +let typed_map f t = f (body_of_type t) +let typed_unmap f t = make_typed_lazy (f t) (fun _ -> assert false) +(**) let frterm_of v = v.term let is_val v = v.norm @@ -579,8 +686,6 @@ let rec traverse_term env t = term = FOP2 (op, traverse_term env a, traverse_term env b)} | DOPN (op,v) -> { norm = false; term = FOPN (op, Array.map (traverse_term env) v) } - | DOPL (op,l) -> - { norm = false; term = FOPL (op, List.map (traverse_term env) l) } | DLAM (x,a) -> { norm = false; term = FLAM (x, traverse_term (subs_lift env) a, a, env) } @@ -588,9 +693,24 @@ let rec traverse_term env t = { norm = (ve=[||]); term = FLAMV (x, Array.map (traverse_term (subs_lift env)) ve, ve, env) } + | CLam (n,t,c) -> + { norm = false; + term = FLam (n, traverse_type env t, traverse_term (subs_lift env) c, + c, env) } + | CPrd (n,t,c) -> + { norm = false; + term = FPrd (n, traverse_type env t, traverse_term (subs_lift env) c, + c, env) } + | CLet (n,b,t,c) -> + { norm = false; + term = FLet (n, traverse_term env b, traverse_type env t, + traverse_term (subs_lift env) c, + c, env) } + +and traverse_type env = typed_map (traverse_term env) (* Back to regular terms: remove all FFROZEN, keep casts (since this - * fun is not dedicated to the Calulus of Constructions). + * fun is not dedicated to the Calculus of Constructions). *) let rec lift_term_of_freeze lfts v = match v.term with @@ -601,10 +721,19 @@ let rec lift_term_of_freeze lfts v = | FOP2 (op,a,b) -> DOP2 (op, lift_term_of_freeze lfts a, lift_term_of_freeze lfts b) | FOPN (op,ve) -> DOPN (op, Array.map (lift_term_of_freeze lfts) ve) - | FOPL (op,l) -> DOPL (op, List.map (lift_term_of_freeze lfts) l) | FLAM (x,a,_,_) -> DLAM (x, lift_term_of_freeze (el_lift lfts) a) | FLAMV (x,ve,_,_) -> DLAMV (x, Array.map (lift_term_of_freeze (el_lift lfts)) ve) + | FLam (n,t,c,_,_) -> + CLam (n, typed_unmap (lift_term_of_freeze lfts) t, + lift_term_of_freeze (el_lift lfts) c) + | FPrd (n,t,c,_,_) -> + CPrd (n, typed_unmap (lift_term_of_freeze lfts) t, + lift_term_of_freeze (el_lift lfts) c) + | FLet (n,b,t,c,_,_) -> + CLet (n, lift_term_of_freeze lfts b, + typed_unmap (lift_term_of_freeze lfts) t, + lift_term_of_freeze (el_lift lfts) c) | FLIFT (k,a) -> lift_term_of_freeze (el_shft k lfts) a | FFROZEN (t,env) -> let unfv = freeze_assign v (traverse_term env t) in @@ -629,30 +758,34 @@ let rec fstrong unfreeze_fun lfts v = | FOP2 (op,a,b) -> DOP2 (op, fstrong unfreeze_fun lfts a, fstrong unfreeze_fun lfts b) | FOPN (op,ve) -> DOPN (op, Array.map (fstrong unfreeze_fun lfts) ve) - | FOPL (op,l) -> DOPL (op, List.map (fstrong unfreeze_fun lfts) l) | FLAM (x,a,_,_) -> DLAM (x, fstrong unfreeze_fun (el_lift lfts) a) | FLAMV (x,ve,_,_) -> DLAMV (x, Array.map (fstrong unfreeze_fun (el_lift lfts)) ve) + | FLam (n,t,c,_,_) -> + CLam (n, typed_unmap (fstrong unfreeze_fun lfts) t, + fstrong unfreeze_fun (el_lift lfts) c) + | FPrd (n,t,c,_,_) -> + CPrd (n, typed_unmap (fstrong unfreeze_fun lfts) t, + fstrong unfreeze_fun (el_lift lfts) c) + | FLet (n,b,t,c,_,_) -> + CLet (n, fstrong unfreeze_fun lfts b, + typed_unmap (fstrong unfreeze_fun lfts) t, + fstrong unfreeze_fun (el_lift lfts) c) | FLIFT (k,a) -> fstrong unfreeze_fun (el_shft k lfts) a | FFROZEN _ -> anomaly "Closure.fstrong" -(* Build a freeze, which represents the substitution of arg in fun_body. +(* Build a freeze, which represents the substitution of arg in t * Used to constract a beta-redex: - * [^depth](FLAM(S,t)) arg -> [(^depth o S).arg]t - * We also deal with FLIFT that would have been inserted between the - * Lambda and FLAM operators. This never happens in practice. + * [^depth](FLam(S,t)) arg -> [(^depth o S).arg]t *) -let rec contract_subst depth fun_body arg = - match fun_body.term with - FLAM(_,_,t,subs) -> freeze (subs_cons (arg, subs_shft (depth,subs))) t - | FLIFT(k,fb) -> contract_subst (depth+k) fb arg - | _ -> anomaly "Closure.contract_subst: malformed function" +let rec contract_subst depth t subs arg = + freeze (subs_cons (arg, subs_shft (depth,subs))) t (* Calculus of Constructions *) -type fconstr = sorts oper freeze +type fconstr = freeze let inject constr = freeze ESID constr @@ -760,6 +893,7 @@ and whnf_frterm info ft = | None -> { norm = array_for_all is_val vars; term = ft.term }) else ft + | FOPN (MutCase ci,cl) -> if red_under info.i_flags IOTA then let c = unfreeze (infos_under info) cl.(1) in @@ -777,8 +911,11 @@ and whnf_frterm info ft = else ft - | FRel _ | FVAR _ | FOP0 _ -> { norm = true; term = ft.term } - | _ -> ft + | FLet (na,b,_,_,t,subs) -> warning "Should be catch in whnf_term"; + contract_subst 0 t subs b + + | FRel _ | FVAR _ | FOP0 _ -> { norm = true; term = ft.term } + | FOPN _ | FOP2 _ | FOP1 _ | FLam _ | FPrd _ | FLAM _ | FLAMV _ -> ft (* Weak head reduction: case of the application (head appl) *) and whnf_apply info head appl = @@ -788,8 +925,8 @@ and whnf_apply info head appl = else let (lft_hd,whd,args) = strip_frterm 0 head [appl] in match whd.term with - | FOP2(Lambda,_,b) when red_under info.i_flags BETA -> - let vbody = contract_subst lft_hd (unfreeze info b) args.(0) in + | FLam (_,_,_,t,subs) when red_under info.i_flags BETA -> + let vbody = contract_subst lft_hd t subs args.(0) in whnf_apply info vbody (array_tl args) | (FOPN(Fix(reci,bnum), tb) as fx) when red_under info.i_flags IOTA @@ -815,21 +952,30 @@ and whnf_term info env t = | DOP0 op -> {norm = true; term = FOP0 op } | DOP1 (op, nt) -> { norm = false; term = FOP1 (op, freeze env nt) } | DOP2 (Cast,ct,c) -> whnf_term info env ct (* remove outer casts *) - | DOP2 (op,a,b) -> (* Lambda Prod *) - { norm = false; term = FOP2 (op, freeze env a, freeze env b) } + | DOP2 (_,_,_) -> assert false (* Lambda|Prod made explicit *) | DOPN ((AppL | Const _ | Evar _ | Abst _ | MutCase _) as op, ve) -> whnf_frterm info { norm = false; term = FOPN (op, freeze_vect env ve) } | DOPN ((MutInd _ | MutConstruct _) as op,v) -> { norm = (v=[||]); term = FOPN (op, freeze_vect env v) } | DOPN (op,v) -> { norm = false; term = FOPN (op, freeze_vect env v) } (* Fix CoFix *) - | DOPL (op,l) -> { norm = false; term = FOPL (op, freeze_list env l) } | DLAM (x,a) -> { norm = false; term = FLAM (x, freeze (subs_lift env) a, a, env) } | DLAMV (x,ve) -> { norm = (ve=[||]); term = FLAMV (x, freeze_vect (subs_lift env) ve, ve, env) } - + | CLam (n,t,c) -> + { norm = false; + term = FLam (n, typed_map (freeze env) t, freeze (subs_lift env) c, + c, env) } + | CPrd (n,t,c) -> + { norm = false; + term = FPrd (n, typed_map (freeze env) t, freeze (subs_lift env) c, + c, env) } + + (* WHNF removes LetIn (see Paula Severi) *) + | CLet (n,b,t,c) -> whnf_term info (subs_cons (freeze env b,env)) c + (* parameterized norm *) let norm_val info v = if !stats then begin diff --git a/kernel/closure.mli b/kernel/closure.mli index 0cba4cb87..940cd2664 100644 --- a/kernel/closure.mli +++ b/kernel/closure.mli @@ -4,7 +4,7 @@ (*i*) open Pp open Names -open Generic +(*i open Generic i*) open Term open Evd open Environ @@ -54,17 +54,29 @@ val betadeltaiota : flags val hnf_flags : flags +(*s Explicit substitutions of type ['a]. [ESID] = identity. + [CONS(t,S)] = $S.t$ i.e. parallel substitution. [SHIFT(n,S)] = + $(\uparrow n~o~S)$ i.e. terms in S are relocated with n vars. + [LIFT(n,S)] = $(\%n~S)$ stands for $((\uparrow n~o~S).n...1)$. *) +type 'a subs = + | ESID + | CONS of 'a * 'a subs + | SHIFT of int * 'a subs + | LIFT of int * 'a subs (*s Call by value functions *) type cbv_value = | VAL of int * constr | LAM of name * constr * constr * cbv_value subs - | FIXP of sorts oper * constr array * cbv_value subs * cbv_value list + | FIXP of fixpoint * cbv_value subs * cbv_value list + | COFIXP of cofixpoint * cbv_value subs * cbv_value list | CONSTR of int * (section_path * int) * cbv_value array * cbv_value list val shift_value : int -> cbv_value -> cbv_value -val contract_fixp : cbv_value subs -> constr -> cbv_value subs * constr +(*i Private ?? +val contract_fixp : cbv_value subs -> fixpoint -> cbv_value subs * constr +i*) type stack = | TOP @@ -78,8 +90,10 @@ val strip_appl : cbv_value -> stack -> cbv_value * stack val red_allowed : flags -> stack -> red_kind -> bool val reduce_const_body : (cbv_value -> cbv_value) -> cbv_value -> stack -> cbv_value * stack +(*i Private ?? val fixp_reducible : - (cbv_value -> cbv_value) -> flags -> sorts oper -> stack -> bool + (cbv_value -> cbv_value) -> flags -> fixpoint -> stack -> bool +i*) (* normalization of a constr: the two functions to know... *) type 'a cbv_infos @@ -99,45 +113,49 @@ val cbv_norm_value : 'a cbv_infos -> cbv_value -> constr (*s Lazy reduction. *) -type 'a freeze +type freeze -type 'a frterm = +type frterm = | FRel of int | FVAR of identifier - | FOP0 of 'a - | FOP1 of 'a * 'a freeze - | FOP2 of 'a * 'a freeze * 'a freeze - | FOPN of 'a * 'a freeze array - | FOPL of 'a * 'a freeze list - | FLAM of name * 'a freeze * 'a term * 'a freeze subs - | FLAMV of name * 'a freeze array * 'a term array * 'a freeze subs - | FLIFT of int * 'a freeze - | FFROZEN of 'a term * 'a freeze subs + | FOP0 of sorts oper + | FOP1 of sorts oper * freeze + | FOP2 of sorts oper * freeze * freeze + | FOPN of sorts oper * freeze array + | FLAM of name * freeze * constr * freeze subs + | FLAMV of name * freeze array * constr array * freeze subs + | FLam of name * type_freeze * freeze * constr * freeze subs + | FPrd of name * type_freeze * freeze * constr * freeze subs + | FLet of name * freeze * type_freeze * freeze * constr * freeze subs + | FLIFT of int * freeze + | FFROZEN of constr * freeze subs -val frterm_of : 'a freeze -> 'a frterm -val is_val : 'a freeze -> bool +and type_freeze = freeze -val lift_frterm : int -> 'a freeze -> 'a freeze -val lift_freeze : int -> 'a freeze -> 'a freeze +val frterm_of : freeze -> frterm +val is_val : freeze -> bool -val freeze : 'a freeze subs -> 'a term -> 'a freeze -val freeze_vect : 'a freeze subs -> 'a term array -> 'a freeze array -val freeze_list : 'a freeze subs -> 'a term list -> 'a freeze list +val lift_frterm : int -> freeze -> freeze +val lift_freeze : int -> freeze -> freeze -val traverse_term : 'a freeze subs -> 'a term -> 'a freeze -val lift_term_of_freeze : lift_spec -> 'a freeze -> 'a term +val freeze : freeze subs -> constr -> freeze +val freeze_vect : freeze subs -> constr array -> freeze array +val freeze_list : freeze subs -> constr list -> freeze list + +val traverse_term : freeze subs -> constr -> freeze +val lift_term_of_freeze : lift_spec -> freeze -> constr (* Back to constr *) -val fstrong : ('a freeze -> 'a freeze) -> lift_spec -> 'a freeze -> 'a term -val term_of_freeze : 'a freeze -> 'a term -val applist_of_freeze : 'a freeze array -> 'a term list +val fstrong : (freeze -> freeze) -> lift_spec -> freeze -> constr +val term_of_freeze : freeze -> constr +val applist_of_freeze : freeze array -> constr list (* contract a substitution *) -val contract_subst : int -> 'a freeze -> 'a freeze -> 'a freeze +val contract_subst : int -> constr -> freeze subs -> freeze -> freeze (* Calculus of Constructions *) -type fconstr = sorts oper freeze +type fconstr = freeze val inject : constr -> fconstr val strip_frterm : @@ -146,7 +164,7 @@ val strip_freeze : fconstr -> int * fconstr * fconstr array (* Auxiliary functions for (co)fixpoint reduction *) -val contract_fix_vect : (fconstr -> fconstr) -> sorts oper frterm -> fconstr +val contract_fix_vect : (fconstr -> fconstr) -> frterm -> fconstr val copy_case : case_info -> fconstr array -> fconstr -> fconstr diff --git a/kernel/declarations.ml b/kernel/declarations.ml index e83e1e509..a5cb164d0 100644 --- a/kernel/declarations.ml +++ b/kernel/declarations.ml @@ -3,7 +3,7 @@ open Names open Univ -open Generic +(*i open Generic i*) open Term open Sign diff --git a/kernel/environ.ml b/kernel/environ.ml index 217a7f989..4909e4444 100644 --- a/kernel/environ.ml +++ b/kernel/environ.ml @@ -6,7 +6,7 @@ open Util open Names open Sign open Univ -open Generic +(*i open Generic i*) open Term open Declarations open Abstraction @@ -229,32 +229,40 @@ let id_of_global env = function assert false let hdchar env c = - let rec hdrec k = function - | DOP2((Prod|Lambda),_,DLAM(_,c)) -> hdrec (k+1) c - | DOP2(Cast,c,_) -> hdrec k c - | DOPN(AppL,cl) -> hdrec k (array_hd cl) - | DOPN(Const _,_) as x -> - let c = lowercase_first_char (basename (path_of_const x)) in + let rec hdrec k c = + match kind_of_term c with + | IsProd (_,_,c) -> hdrec (k+1) c + | IsLambda (_,_,c) -> hdrec (k+1) c + | IsLetIn (_,_,_,c) -> hdrec (k+1) c + | IsCast (c,_) -> hdrec k c + | IsAppL (f,l) -> hdrec k f + | IsConst (sp,_) -> + let c = lowercase_first_char (basename sp) in if c = "?" then "y" else c - | DOPN(Abst _,_) as x -> - lowercase_first_char (basename (path_of_abst x)) - | DOPN(MutInd (sp,i) as x,_) -> + | IsMutInd ((sp,i) as x,_) -> if i=0 then lowercase_first_char (basename sp) else - let na = id_of_global env x in lowercase_first_char na - | DOPN(MutConstruct(sp,i) as x,_) -> - let na = id_of_global env x in String.lowercase(List.hd(explode_id na)) - | VAR id -> lowercase_first_char id - | DOP0(Sort s) -> sort_hdchar s - | Rel n -> + let na = id_of_global env (MutInd x) in lowercase_first_char na + | IsMutConstruct ((sp,i) as x,_) -> + let na = id_of_global env (MutConstruct x) in + String.lowercase(List.hd(explode_id na)) + | IsVar id -> lowercase_first_char id + | IsSort s -> sort_hdchar s + | IsRel n -> (if n<=k then "p" (* the initial term is flexible product/function *) else try match lookup_rel_type (n-k) env with | Name id,_ -> lowercase_first_char id | Anonymous,t -> hdrec 0 (lift (n-k) (body_of_type t)) with Not_found -> "y") - | _ -> "y" + | IsFix ((_,i),(_,ln,_)) -> + let id = match List.nth ln i with Name id -> id | _ -> assert false in + lowercase_first_char id + | IsCoFix (i,(_,ln,_)) -> + let id = match List.nth ln i with Name id -> id | _ -> assert false in + lowercase_first_char id + | IsMeta _|IsXtra _|IsAbst (_, _)|IsEvar _|IsMutCase (_, _, _, _) -> "y" in hdrec 0 c @@ -266,14 +274,14 @@ let named_hd env a = function | Anonymous -> Name (id_of_string (hdchar env a)) | x -> x -let prod_name env (n,a,b) = mkProd (named_hd env a n) a b -let lambda_name env (n,a,b) = mkLambda (named_hd env a n) a b +let prod_name env (n,a,b) = mkProd (named_hd env a n, a, b) +let lambda_name env (n,a,b) = mkLambda (named_hd env a n, a, b) let it_prod_name env = List.fold_left (fun c (n,t) ->prod_name env (n,t,c)) let it_lambda_name env = List.fold_left (fun c (n,t) ->lambda_name env (n,t,c)) -let prod_create env (a,b) = mkProd (named_hd env a Anonymous) a b -let lambda_create env (a,b) = mkLambda (named_hd env a Anonymous) a b +let prod_create env (a,b) = mkProd (named_hd env a Anonymous, a, b) +let lambda_create env (a,b) = mkLambda (named_hd env a Anonymous, a, b) let name_assumption env (na,c,t) = match c with @@ -286,6 +294,7 @@ let lambda_assum_name env b d = mkLambda_or_LetIn (name_assumption env d) b let it_mkProd_or_LetIn_name env = List.fold_left (prod_assum_name env) let it_mkLambda_or_LetIn_name env = List.fold_left (lambda_assum_name env) +let it_mkProd_wo_LetIn = List.fold_left (fun c d -> mkProd_wo_LetIn d c) let it_mkProd_or_LetIn = List.fold_left (fun c d -> mkProd_or_LetIn d c) let it_mkLambda_or_LetIn = List.fold_left (fun c d -> mkLambda_or_LetIn d c) diff --git a/kernel/environ.mli b/kernel/environ.mli index 981be607f..b99410bd3 100644 --- a/kernel/environ.mli +++ b/kernel/environ.mli @@ -130,6 +130,7 @@ val it_prod_name : env -> constr -> (name * constr) list -> constr val it_mkLambda_or_LetIn_name : env -> constr -> rel_context -> constr val it_mkProd_or_LetIn_name : env -> constr -> rel_context -> constr +val it_mkProd_wo_LetIn : constr -> rel_context -> constr val it_mkLambda_or_LetIn : constr -> rel_context -> constr val it_mkProd_or_LetIn : constr -> rel_context -> constr diff --git a/kernel/indtypes.ml b/kernel/indtypes.ml index 0536b1f2f..a37e469bd 100644 --- a/kernel/indtypes.ml +++ b/kernel/indtypes.ml @@ -3,7 +3,7 @@ open Util open Names -open Generic +(*i open Generic i*) open Term open Declarations open Inductive @@ -92,14 +92,6 @@ let mind_extract_and_check_params mie = List.iter (fun (_,c,_,_) -> check_params params (extract nparams c)) l; params -let decomp_all_DLAMV_name constr = - let rec decomprec lna = function - | DLAM(na,lc) -> decomprec (na::lna) lc - | DLAMV(na,lc) -> (na::lna,lc) - | _ -> assert false - in - decomprec [] constr - let mind_check_lc params mie = let nparams = List.length params in let check_lc (_,_,_,lc) = @@ -156,6 +148,7 @@ let failwith_non_pos_vect n ntypes v = anomaly "failwith_non_pos_vect: some k in [n;n+ntypes-1] should occur in v" let check_correct_par env nparams ntypes n l largs = + let largs = Array.of_list largs in if Array.length largs < nparams then raise (IllFormedInd (LocalNotEnoughArgs l)); let (lpar,largs') = array_chop nparams largs in @@ -182,40 +175,40 @@ let decomp_par n c = snd (mind_extract_params n c) let listrec_mconstr env ntypes nparams i indlc = (* check the inductive types occur positively in [c] *) let rec check_pos n c = - match whd_betadeltaiota env Evd.empty c with - | DOP2(Prod,b,DLAM(na,d)) -> - if not (noccur_between n ntypes b) then raise (IllFormedInd (LocalNonPos n)); + let x,largs = whd_betadeltaiota_stack env Evd.empty c [] in + match kind_of_term x with + | IsProd (na,b,d) -> + assert (largs = []); + if not (noccur_between n ntypes b) then + raise (IllFormedInd (LocalNonPos n)); check_pos (n+1) d - | x -> - let hd,largs = destApplication (ensure_appl x) in - match hd with - | Rel k -> - if k >= n && k<n+ntypes then begin - check_correct_par env nparams ntypes n (k-n+1) largs; - Mrec(n+ntypes-k-1) - end else if noccur_between n ntypes x then - if (n-nparams) <= k & k <= (n-1) - then Param(n-1-k) - else Norec - else - raise (IllFormedInd (LocalNonPos n)) - | DOPN(MutInd ind_sp,a) -> - if (noccur_between n ntypes x) then Norec - else Imbr(ind_sp,imbr_positive n (ind_sp,a) largs) - | err -> - if noccur_between n ntypes x then Norec - else raise (IllFormedInd (LocalNonPos n)) + | IsRel k -> + if k >= n && k<n+ntypes then begin + check_correct_par env nparams ntypes n (k-n+1) largs; + Mrec(n+ntypes-k-1) + end else if noccur_between n ntypes x then + if (n-nparams) <= k & k <= (n-1) + then Param(n-1-k) + else Norec + else + raise (IllFormedInd (LocalNonPos n)) + | IsMutInd (ind_sp,a) -> + if (noccur_between n ntypes x) then Norec + else Imbr(ind_sp,imbr_positive n (ind_sp,a) largs) + | err -> + if noccur_between n ntypes x then Norec + else raise (IllFormedInd (LocalNonPos n)) and imbr_positive n mi largs = let mispeci = lookup_mind_specif mi env in let auxnpar = mis_nparams mispeci in - let (lpar,auxlargs) = array_chop auxnpar largs in - if not (array_for_all (noccur_between n ntypes) auxlargs) then + let (lpar,auxlargs) = list_chop auxnpar largs in + if not (List.for_all (noccur_between n ntypes) auxlargs) then raise (IllFormedInd (LocalNonPos n)); let auxlc = mis_lc mispeci and auxntyp = mis_ntypes mispeci in if auxntyp <> 1 then raise (IllFormedInd (LocalNonPos n)); - let lrecargs = array_map_to_list (check_weak_pos n) lpar in + let lrecargs = List.map (check_weak_pos n) lpar in (* The abstract imbricated inductive type with parameters substituted *) let auxlcvect = abstract_mind_lc env auxntyp auxnpar auxlc in let newidx = n + auxntyp in @@ -224,8 +217,8 @@ let listrec_mconstr env ntypes nparams i indlc = (* when substituted *) Array.map (function c -> - let c' = hnf_prod_appvect env Evd.empty c - (Array.map (lift auxntyp) lpar) in + let c' = hnf_prod_applist env Evd.empty c + (List.map (lift auxntyp) lpar) in check_construct false newidx c') auxlcvect in @@ -248,15 +241,16 @@ let listrec_mconstr env ntypes nparams i indlc = (* Since Lambda can no longer occur after a product or a MutInd, I have branched the remaining cases on check_pos. HH 28/1/00 *) - and check_weak_pos n c = - match whd_betadeltaiota env Evd.empty c with + and check_weak_pos n c = + let x = whd_betadeltaiota env Evd.empty c in + match kind_of_term x with (* The extra case *) - | DOP2(Lambda,b,DLAM(na,d)) -> + | IsLambda (na,b,d) -> if noccur_between n ntypes b then check_weak_pos (n+1) d else raise (IllFormedInd (LocalNonPos n)) (******************) - | x -> check_pos n x + | _ -> check_pos n x (* check the inductive types occur positively in the products of C, if check_head=true, also check the head corresponds to a constructor of @@ -264,19 +258,20 @@ let listrec_mconstr env ntypes nparams i indlc = and check_construct check_head = let rec check_constr_rec lrec n c = - match whd_betadeltaiota env Evd.empty c with - | DOP2(Prod,b,DLAM(na,d)) -> + let x,largs = whd_betadeltaiota_stack env Evd.empty c [] in + match kind_of_term x with + | IsProd (na,b,d) -> + assert (largs = []); let recarg = check_pos n b in check_constr_rec (recarg::lrec) (n+1) d - | x -> - let hd,largs = destApplication (ensure_appl x) in + | hd -> if check_head then - match hd with - | Rel k when k = n+ntypes-i -> - check_correct_par env nparams ntypes n (k-n+1) largs - | _ -> raise (IllFormedInd LocalNotConstructor) + if hd = IsRel (n+ntypes-i) then + check_correct_par env nparams ntypes n (ntypes-i+1) largs + else + raise (IllFormedInd LocalNotConstructor) else - if not (array_for_all (noccur_between n ntypes) largs) + if not (List.for_all (noccur_between n ntypes) largs) then raise (IllFormedInd (LocalNonPos n)); List.rev lrec in check_constr_rec [] diff --git a/kernel/inductive.ml b/kernel/inductive.ml index 43b756651..db3329a1a 100644 --- a/kernel/inductive.ml +++ b/kernel/inductive.ml @@ -4,7 +4,7 @@ open Util open Names open Univ -open Generic +(*i open Generic i*) open Term open Sign open Declarations diff --git a/kernel/instantiate.ml b/kernel/instantiate.ml index 9fb85961f..627f0d45c 100644 --- a/kernel/instantiate.ml +++ b/kernel/instantiate.ml @@ -4,7 +4,7 @@ open Pp open Util open Names -open Generic +(*i open Generic i*) open Term open Sign open Evd diff --git a/kernel/reduction.ml b/kernel/reduction.ml index c4642b933..f0f7945d6 100644 --- a/kernel/reduction.ml +++ b/kernel/reduction.ml @@ -4,7 +4,7 @@ open Pp open Util open Names -open Generic +(*i open Generic i*) open Term open Univ open Evd @@ -26,6 +26,17 @@ type 'a stack_reduction_function = 'a contextual_stack_reduction_function type local_stack_reduction_function = constr -> constr list -> constr * constr list +type stack = + | EmptyStack + | ConsStack of constr array * int * stack + +let decomp_stack = function + | EmptyStack -> None + | ConsStack (v, n, s) -> + Some (v.(n), (if n+1 = Array.length v then s else ConsStack (v, n+1, s))) + +let append_stack v s = if Array.length v = 0 then s else ConsStack (v,0,s) + (*************************************) (*** Reduction Functions Operators ***) (*************************************) @@ -49,44 +60,66 @@ let stack_reduction_of_reduction red_fun env sigma x stack = whd_stack t [] let strong whdfun env sigma = - let rec strongrec t = match whdfun env sigma t with + let rec strongrec env t = match whdfun env sigma t with | DOP0 _ as t -> t + | DOP1(oper,c) -> DOP1(oper,strongrec env c) + | DOP2(oper,c1,c2) -> DOP2(oper,strongrec env c1,strongrec env c2) (* Cas ad hoc *) - | DOP1(oper,c) -> DOP1(oper,strongrec c) - (* Faut differencier sinon fait planter kind_of_term *) - | DOP2(Prod|Lambda as oper,c1,DLAM(na,c2)) -> - DOP2(oper,strongrec c1,DLAM(na,strongrec c2)) - | DOP2(oper,c1,c2) -> DOP2(oper,strongrec c1,strongrec c2) - | DOPN(oper,cl) -> DOPN(oper,Array.map strongrec cl) - | DOPL(oper,cl) -> DOPL(oper,List.map strongrec cl) - | DLAM(na,c) -> DLAM(na,strongrec c) - | DLAMV(na,c) -> DLAMV(na,Array.map strongrec c) + | DOPN(Fix _ as oper,cl) -> + let cl' = Array.copy cl in + let l = Array.length cl -1 in + for i=0 to l-1 do cl'.(i) <- strongrec env cl.(i) done; + cl'.(l) <- strongrec_lam env cl.(l); + DOPN(oper, cl') + | DOPN(oper,cl) -> DOPN(oper,Array.map (strongrec env) cl) + | CLam (n,t,c) -> + CLam (n, typed_app (strongrec env) t, strongrec (push_rel_decl (n,t) env) c) + | CPrd (n,t,c) -> + CPrd (n, typed_app (strongrec env) t, strongrec (push_rel_decl (n,t) env) c) + | CLet (n,b,t,c) -> + CLet (n, strongrec env b, typed_app (strongrec env) t, + strongrec (push_rel_def (n,b,t) env) c) | VAR _ as t -> t | Rel _ as t -> t + | DLAM _ | DLAMV _ -> assert false + and strongrec_lam env = function (* Gestion incorrecte de l'env des Fix *) + | DLAM(na,c) -> DLAM(na,strongrec_lam env c) + | DLAMV(na,c) -> DLAMV(na,Array.map (strongrec env) c) + | _ -> assert false in - strongrec + strongrec env let local_strong whdfun = let rec strongrec t = match whdfun t with | DOP0 _ as t -> t - (* Cas ad hoc *) | DOP1(oper,c) -> DOP1(oper,strongrec c) | DOP2(oper,c1,c2) -> DOP2(oper,strongrec c1,strongrec c2) + (* Cas ad hoc *) + | DOPN(Fix _ as oper,cl) -> + let cl' = Array.copy cl in + let l = Array.length cl -1 in + for i=0 to l-1 do cl'.(i) <- strongrec cl.(i) done; + cl'.(l) <- strongrec_lam cl.(l); + DOPN(oper, cl') | DOPN(oper,cl) -> DOPN(oper,Array.map strongrec cl) - | DOPL(oper,cl) -> DOPL(oper,List.map strongrec cl) - | DLAM(na,c) -> DLAM(na,strongrec c) - | DLAMV(na,c) -> DLAMV(na,Array.map strongrec c) + | CLam(n,t,c) -> CLam (n, typed_app strongrec t, strongrec c) + | CPrd(n,t,c) -> CPrd (n, typed_app strongrec t, strongrec c) + | CLet(n,b,t,c) -> CLet (n, strongrec b,typed_app strongrec t, strongrec c) | VAR _ as t -> t | Rel _ as t -> t + | DLAM _ | DLAMV _ -> assert false + and strongrec_lam = function + | DLAM(na,c) -> DLAM(na,strongrec_lam c) + | DLAMV(na,c) -> DLAMV(na,Array.map strongrec c) + | _ -> assert false in strongrec -let rec strong_prodspine redfun env sigma c = - match redfun env sigma c with - | DOP2(Prod,a,DLAM(na,b)) -> - DOP2(Prod,a,DLAM(na,strong_prodspine redfun env sigma b)) - | x -> x - +let rec strong_prodspine redfun c = + let x = redfun c in + match kind_of_term x with + | IsProd (na,a,b) -> mkProd (na,a,strong_prodspine redfun b) + | _ -> x (****************************************************************************) (* Reduction Functions *) @@ -122,17 +155,14 @@ let whd_flags flgs env sigma t = (* Red reduction tactic: reduction to a product *) let red_product env sigma c = let rec redrec x = - match x with - | DOPN(AppL,cl) -> - DOPN(AppL,Array.append [|redrec (array_hd cl)|] (array_tl cl)) - | DOPN(Const _,_) when evaluable_constant env x -> - constant_value env x - | DOPN(Evar ev,args) when Evd.is_defined sigma ev -> + match kind_of_term x with + | IsAppL (f,l) -> applist (redrec f, l) + | IsConst (_,_) when evaluable_constant env x -> constant_value env x + | IsEvar (ev,args) when Evd.is_defined sigma ev -> existential_value sigma (ev,args) - | DOPN(Abst _,_) when evaluable_abst env x -> - abst_value env x - | DOP2(Cast,c,_) -> redrec c - | DOP2(Prod,a,DLAM(x,b)) -> DOP2(Prod, a, DLAM(x, redrec b)) + | IsAbst (_,_) when evaluable_abst env x -> abst_value env x + | IsCast (c,_) -> redrec c + | IsProd (x,a,b) -> mkProd (x, a, redrec b) | _ -> error "Term not reducible" in nf_betaiota env sigma (redrec c) @@ -141,33 +171,26 @@ let red_product env sigma 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 c with - | DOPN(Const sp,_) -> - if sp = name then - if List.hd ol = n then - if evaluable_constant env c then - (n+1, List.tl ol, constant_value env c) - else - errorlabstrm "substlin" - [< print_sp sp; 'sTR " is not a defined constant" >] - else - ((n+1),ol,c) + match kind_of_term c with + | IsConst (sp,_) when sp = name -> + if List.hd ol = n then + if evaluable_constant env c then + (n+1, List.tl ol, constant_value env c) + else + errorlabstrm "substlin" + [< print_sp sp; 'sTR " is not a defined constant" >] else - (n,ol,c) + ((n+1),ol,c) - | DOPN(Abst _,_) -> - if path_of_abst c = name then - if List.hd ol = n then - (n+1, List.tl ol, abst_value env c) - else - (n+1,ol,c) + | IsAbst (_,_) when path_of_abst c = name -> + if List.hd ol = n then + (n+1, List.tl ol, abst_value env c) else - (n,ol,c) + (n+1,ol,c) (* INEFFICIENT: OPTIMIZE *) - | DOPN(AppL,tl) -> - let c1 = array_hd tl and cl = array_tl tl in - Array.fold_left + | IsAppL (c1,cl) -> + List.fold_left (fun (n1,ol1,c1') c2 -> (match ol1 with | [] -> (n1,[],applist(c1',[c2])) @@ -176,24 +199,31 @@ let rec substlin env name n ol c = (n2,ol2,applist(c1',[c2'])))) (substlin env name n ol c1) cl - | DOP2(Lambda,c1,DLAM(na,c2)) -> + | IsLambda (na,c1,c2) -> let (n1,ol1,c1') = substlin env name n ol c1 in (match ol1 with - | [] -> (n1,[],DOP2(Lambda,c1',DLAM(na,c2))) + | [] -> (n1,[],mkLambda (na,c1',c2)) | _ -> let (n2,ol2,c2') = substlin env name n1 ol1 c2 in - (n2,ol2,DOP2(Lambda,c1',DLAM(na,c2')))) + (n2,ol2,mkLambda (na,c1',c2'))) - | DOP2(Prod,c1,DLAM(na,c2)) -> + | IsLetIn (na,c1,t,c2) -> let (n1,ol1,c1') = substlin env name n ol c1 in (match ol1 with - | [] -> (n1,[],DOP2(Prod,c1',DLAM(na,c2))) + | [] -> (n1,[],mkLambda (na,c1',c2)) | _ -> let (n2,ol2,c2') = substlin env name n1 ol1 c2 in - (n2,ol2,DOP2(Prod,c1',DLAM(na,c2')))) + (n2,ol2,mkLambda (na,c1',c2'))) + + | IsProd (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'))) - | DOPN(MutCase _,_) -> - let (ci,p,d,llf) = destCase c in + | IsMutCase (ci,p,d,llf) -> let rec substlist nn oll = function | [] -> (nn,oll,[]) | f::lfe -> @@ -213,23 +243,26 @@ let rec substlin env name n ol c = | [] -> (n2,[],mkMutCaseA ci p' d' llf) | _ -> let (n3,ol3,lf') = substlist n2 ol2 (Array.to_list llf) - in (n3,ol3,mkMutCase ci p' d' lf'))) + in (n3,ol3,mkMutCase (ci, p', d', lf')))) - | DOP2(Cast,c1,c2) -> + | IsCast (c1,c2) -> let (n1,ol1,c1') = substlin env name n ol c1 in (match ol1 with - | [] -> (n1,[],DOP2(Cast,c1',c2)) + | [] -> (n1,[],mkCast (c1',c2)) | _ -> let (n2,ol2,c2') = substlin env name n1 ol1 c2 in - (n2,ol2,DOP2(Cast,c1',c2'))) + (n2,ol2,mkCast (c1',c2'))) - | DOPN(Fix _,_) -> + | IsFix _ -> (warning "do not consider occurrences inside fixpoints"; (n,ol,c)) - | DOPN(CoFix _,_) -> + | IsCoFix _ -> (warning "do not consider occurrences inside cofixpoints"; (n,ol,c)) + + | (IsRel _|IsMeta _|IsVar _|IsXtra _|IsSort _ + |IsAbst (_, _)|IsEvar _|IsConst _ + |IsMutInd _|IsMutConstruct _) -> (n,ol,c) - | _ -> (n,ol,c) let unfold env sigma name = let flag = @@ -275,9 +308,9 @@ let abstract_scheme env (locc,a,ta) t = 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 - DOP2(Lambda,ta,DLAM(na,t)) + mkLambda (na,ta,t) else - DOP2(Lambda, ta, DLAM(na,subst_term_occ locc a t)) + mkLambda (na, ta,subst_term_occ locc a t) let pattern_occs loccs_trm_typ env sigma c = @@ -293,26 +326,25 @@ let pattern_occs loccs_trm_typ env sigma c = let rec stacklam recfun env t stack = match (stack,t) with - | (h::stacktl, DOP2(Lambda,_,DLAM(_,c))) -> - stacklam recfun (h::env) c stacktl - | _ -> recfun (substl env t) stack + | h::stacktl, CLam (_,_,c) -> stacklam recfun (h::env) c stacktl + | _ -> recfun (substl env t, stack) -let beta_applist (c,l) = stacklam (fun c l -> applist(c,l)) [] c l +let beta_applist (c,l) = stacklam applist [] c l -let whd_beta_stack = - let rec whrec x stack = match x with - | DOP2(Lambda,c1,DLAM(name,c2)) -> +let whd_beta_stack x stack = + let rec whrec (x, stack as s) = match x with + | CLam (name,c1,c2) -> (match stack with | [] -> (x,[]) | a1::rest -> stacklam whrec [a1] c2 rest) - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Cast,c,_) -> whrec c stack - | x -> (x,stack) + | DOPN(AppL,cl) -> whrec (array_hd cl, array_app_tl cl stack) + | DOP2(Cast,c,_) -> whrec (c, stack) + | x -> s in - whrec + whrec (x, stack) let whd_beta x = applist (whd_beta_stack x []) @@ -375,103 +407,105 @@ let whd_delta_stack env sigma = let whd_delta env sigma c = applist(whd_delta_stack env sigma c []) -let whd_betadelta_stack env sigma = - let rec whrec x l = - match x with - | DOPN(Const _,_) -> +let whd_betadelta_stack env sigma x l = + let rec whrec (x, l as s) = + match kind_of_term x with + | IsConst _ -> if evaluable_constant env x then - whrec (constant_value env x) l + whrec (constant_value env x, l) else - (x,l) - | DOPN(Evar ev,args) -> + s + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - whrec (existential_value sigma (ev,args)) l + whrec (existential_value sigma (ev,args), l) else - (x,l) + s +(* | DOPN(Abst _,_) -> if evaluable_abst env x then whrec (abst_value env x) l else (x,l) - | DOP2(Cast,c,_) -> whrec c l - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl l) - | DOP2(Lambda,_,DLAM(_,c)) -> +*) + | IsCast (c,_) -> whrec (c, l) + | IsAppL (f,cl) -> whrec (f, cl@l) + | IsLambda (_,_,c) -> (match l with - | [] -> (x,l) + | [] -> s | (a::m) -> stacklam whrec [a] c m) - | x -> (x,l) + | x -> s in - whrec + whrec (x, l) let whd_betadelta env sigma c = applist(whd_betadelta_stack env sigma c []) -let whd_betaevar_stack env sigma = - let rec whrec x l = - match x with - | DOPN(Evar ev,args) -> +let whd_betaevar_stack env sigma x l = + let rec whrec (x, l as s) = + match kind_of_term x with + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - whrec (existential_value sigma (ev,args)) l + whrec (existential_value sigma (ev,args), l) else - (x,l) + s +(* | DOPN(Abst _,_) -> if translucent_abst env x then whrec (abst_value env x) l else (x,l) - | DOP2(Cast,c,_) -> whrec c l - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl l) - | DOP2(Lambda,_,DLAM(_,c)) -> +*) + | IsCast (c,_) -> whrec (c, l) + | IsAppL (f,cl) -> whrec (f, cl@l) + | IsLambda (_,_,c) -> (match l with | [] -> (x,l) | (a::m) -> stacklam whrec [a] c m) - | DOPN(Const _,_) -> (x,l) - | x -> (x,l) + | x -> s in - whrec + whrec (x, l) let whd_betaevar env sigma c = applist(whd_betaevar_stack env sigma c []) -let whd_betadeltaeta_stack env sigma = - let rec whrec x stack = - match x with - | DOPN(Const _,_) -> - if evaluable_constant env x then - whrec (constant_value env x) stack +let whd_betadeltaeta_stack env sigma x l = + let rec whrec (x, l as s) = + match kind_of_term x with + | IsConst _ -> + if evaluable_constant env x then + whrec (constant_value env x, l) else - (x,stack) - | DOPN(Evar ev,args) -> + s + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - whrec (existential_value sigma (ev,args)) stack + whrec (existential_value sigma (ev,args), l) else - (x,stack) + s +(* | DOPN(Abst _,_) -> - if evaluable_abst env x then - whrec (abst_value env x) stack + if evaluable_abst env x then + whrec (abst_value env x) l else - (x,stack) - | DOP2(Cast,c,_) -> whrec c stack - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> - (match stack with - | [] -> - (match applist (whrec c []) with - | DOPN(AppL,cl) -> - (match whrec (array_last cl) [] with - | (Rel 1,[]) -> - let napp = (Array.length cl) -1 in - if napp = 0 then (x,stack) else - let lc = Array.sub cl 0 napp in - let u = - if napp = 1 then lc.(0) else DOPN(AppL,lc) - in - if noccurn 1 u then (pop u,[]) else (x,stack) - | _ -> (x,stack)) - | _ -> (x,stack)) + (x,l) +*) + | IsCast (c,_) -> whrec (c, l) + | IsAppL (f,cl) -> whrec (f, cl@l) + | IsLambda (_,_,c) -> + (match l with + | [] -> + (match applist (whrec (c, [])) with + | DOPN(AppL,cl) -> + let napp = (Array.length cl) -1 in + (match whrec (array_last cl, []) with + | (Rel 1,[]) when napp > 0 -> + let lc = Array.sub cl 0 napp in + let u = if napp=1 then lc.(0) else DOPN(AppL,lc) + in if noccurn 1 u then (pop u,[]) else s + | _ -> s) + | _ -> s) | (a::m) -> stacklam whrec [a] c m) - | x -> (x,stack) + | x -> s in - whrec + whrec (x, l) let whd_betadeltaeta env sigma x = applist(whd_betadeltaeta_stack env sigma x []) @@ -540,185 +574,185 @@ let fix_recarg ((recindices,bodynum),_) stack = else None +type fix_reduction_result = NotReducible | Reduced of (constr * constr list) + let reduce_fix whfun fix stack = - let dfix = destFix fix in - match fix_recarg dfix stack with - | None -> (false,(fix,stack)) + match fix_recarg fix stack with + | None -> NotReducible | Some (recargnum,recarg) -> - let (recarg'hd,_ as recarg') = whfun recarg [] in + let (recarg'hd,_ as recarg') = whfun (recarg, []) in let stack' = list_assign stack recargnum (applist recarg') in (match recarg'hd with - | DOPN(MutConstruct _,_) -> - (true,(contract_fix dfix,stack')) - | _ -> (false,(fix,stack'))) + | DOPN(MutConstruct _,_) -> Reduced (contract_fix fix, stack') + | _ -> NotReducible) (* NB : Cette fonction alloue peu c'est l'appel ``let (recarg'hd,_ as recarg') = whfun recarg [] in'' -------------------- qui coute cher dans whd_betadeltaiota *) -let whd_betaiota_stack = - let rec whrec x stack = - match x with - | DOP2(Cast,c,_) -> whrec c stack - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> +let whd_betaiota_stack x l = + let rec whrec (x,stack as s) = + match kind_of_term x with + | IsCast (c,_) -> whrec (c, stack) + | IsAppL (f,cl) -> whrec (f, cl@stack) + | IsLambda (_,_,c) -> (match stack with - | [] -> (x,stack) - | (a::m) -> stacklam whrec [a] c m) - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase x in - let (c,cargs) = whrec d [] in + | [] -> s + | a::m -> stacklam whrec [a] c m) + | IsMutCase (ci,p,d,lf) -> + let (c,cargs) = whrec (d, []) in if reducible_mind_case c then whrec (reduce_mind_case - {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}) stack + {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}, stack) else (mkMutCaseA ci p (applist(c,cargs)) lf, stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = reduce_fix whrec x stack in - if reduced then whrec fix stack else (fix,stack) - | x -> (x,stack) + | IsFix fix -> + (match reduce_fix whrec fix stack with + | Reduced s' -> whrec s' + | NotReducible -> s) + | _ -> s in - whrec + whrec (x, l) let whd_betaiota x = applist (whd_betaiota_stack x []) -let whd_betaiotaevar_stack env sigma = - let rec whrec x stack = - match x with - | DOPN(Evar ev,args) -> +let whd_betaiotaevar_stack env sigma x l = + let rec whrec (x, stack as s) = + match kind_of_term x with + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - whrec (existential_value sigma (ev,args)) stack + whrec (existential_value sigma (ev,args), stack) else - (x,stack) + s +(* | DOPN(Abst _,_) -> if translucent_abst env x then whrec (abst_value env x) stack else (x,stack) - | DOP2(Cast,c,_) -> whrec c stack - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> +*) + | IsCast (c,_) -> whrec (c, stack) + | IsAppL (f,cl) -> whrec (f, cl@stack) + | IsLambda (_,_,c) -> (match stack with - | [] -> (x,stack) + | [] -> s | (a::m) -> stacklam whrec [a] c m) - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase x in - let (c,cargs) = whrec d [] in + | IsMutCase (ci,p,d,lf) -> + let (c,cargs) = whrec (d, []) in if reducible_mind_case c then whrec (reduce_mind_case - {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}) stack + {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}, stack) else - (mkMutCaseA ci p (applist(c,cargs)) lf,stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = reduce_fix whrec x stack in - if reduced then whrec fix stack else (fix,stack) - | DOPN(Const _,_) -> (x,stack) - | x -> (x,stack) + (mkMutCaseA ci p (applist(c,cargs)) lf, stack) + | IsFix fix -> + (match reduce_fix whrec fix stack with + | Reduced s' -> whrec s' + | NotReducible -> s) + | _ -> s in - whrec + whrec (x, l) let whd_betaiotaevar env sigma x = applist(whd_betaiotaevar_stack env sigma x []) -let whd_betadeltaiota_stack env sigma = - let rec bdi_rec x stack = - match x with - | DOPN(Const _,_) -> +let whd_betadeltaiota_stack env sigma x l = + let rec whrec (x, stack as s) = + match kind_of_term x with + | IsConst _ -> if evaluable_constant env x then - bdi_rec (constant_value env x) stack + whrec (constant_value env x, stack) else - (x,stack) - | DOPN(Evar ev,args) -> + s + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - bdi_rec (existential_value sigma (ev,args)) stack + whrec (existential_value sigma (ev,args), stack) else - (x,stack) + s +(* | DOPN(Abst _,_) -> if evaluable_abst env x then - bdi_rec (abst_value env x) stack + whrec (abst_value env x) stack else (x,stack) - | DOP2(Cast,c,_) -> bdi_rec c stack - | DOPN(AppL,cl) -> bdi_rec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> +*) + | IsCast (c,_) -> whrec (c, stack) + | IsAppL (f,cl) -> whrec (f, cl@stack) + | IsLambda (_,_,c) -> (match stack with - | [] -> (x,[]) - | (a::m) -> stacklam bdi_rec [a] c m) - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase x in - let (c,cargs) = bdi_rec d [] in + | [] -> s + | (a::m) -> stacklam whrec [a] c m) + | IsMutCase (ci,p,d,lf) -> + let (c,cargs) = whrec (d, []) in if reducible_mind_case c then - bdi_rec (reduce_mind_case - {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}) stack + whrec (reduce_mind_case + {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}, stack) else - (mkMutCaseA ci p (applist(c,cargs)) lf,stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = reduce_fix bdi_rec x stack in - if reduced then bdi_rec fix stack else (fix,stack) - | x -> (x,stack) + (mkMutCaseA ci p (applist(c,cargs)) lf, stack) + | IsFix fix -> + (match reduce_fix whrec fix stack with + | Reduced s' -> whrec s' + | NotReducible -> s) + | _ -> s in - bdi_rec + whrec (x, l) let whd_betadeltaiota env sigma x = applist(whd_betadeltaiota_stack env sigma x []) -let whd_betadeltaiotaeta_stack env sigma = - let rec whrec x stack = - match x with - | DOPN(Const _,_) -> - if evaluable_constant env x then - whrec (constant_value env x) stack +let whd_betadeltaiotaeta_stack env sigma x l = + let rec whrec (x, stack as s) = + match kind_of_term x with + | IsConst _ -> + if evaluable_constant env x then + whrec (constant_value env x, stack) else - (x,stack) - | DOPN(Evar ev,args) -> + s + | IsEvar (ev,args) -> if Evd.is_defined sigma ev then - whrec (existential_value sigma (ev,args)) stack + whrec (existential_value sigma (ev,args), stack) else - (x,stack) + s +(* | DOPN(Abst _,_) -> - if evaluable_abst env x then - whrec (abst_value env x) stack - else + if evaluable_abst env x then + whrec (abst_value env x) stack + else (x,stack) - | DOP2(Cast,c,_) -> whrec c stack - | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> +*) + | IsCast (c,_) -> whrec (c, stack) + | IsAppL (f,cl) -> whrec (f, cl@stack) + | IsLambda (_,_,c) -> (match stack with | [] -> - (match applist (whrec c []) with - | DOPN(AppL,cl) -> - (match whrec (array_last cl) [] with - | (Rel 1,[]) -> - let napp = (Array.length cl) -1 in - if napp = 0 then - (x,stack) - else - let lc = Array.sub cl 0 napp in - let u = - if napp = 1 then lc.(0) else DOPN(AppL,lc) - in - if noccurn 1 u then (pop u,[]) else (x,stack) - | _ -> (x,stack)) - | _ -> (x,stack)) + (match applist (whrec (c, [])) with + | DOPN(AppL,cl) -> + let napp = (Array.length cl) -1 in + (match whrec (array_last cl, []) with + | (Rel 1,[]) when napp > 0 -> + let lc = Array.sub cl 0 napp in + let u = if napp=1 then lc.(0) else DOPN(AppL,lc) + in if noccurn 1 u then (pop u,[]) else s + | _ -> s) + | _ -> s) | (a::m) -> stacklam whrec [a] c m) - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase x in - let (c,cargs) = whrec d [] in + | IsMutCase (ci,p,d,lf) -> + let (c,cargs) = whrec (d, []) in if reducible_mind_case c then whrec (reduce_mind_case - {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}) stack + {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}, stack) else - (mkMutCaseA ci p (applist(c,cargs)) lf,stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = reduce_fix whrec x stack in - if reduced then whrec fix stack else (fix,stack) - | x -> (x,stack) + (mkMutCaseA ci p (applist(c,cargs)) lf, stack) + | IsFix fix -> + (match reduce_fix whrec fix stack with + | Reduced s' -> whrec s' + | NotReducible -> s) + | _ -> s in - whrec + whrec (x, l) let whd_betadeltaiotaeta env sigma x = applist(whd_betadeltaiotaeta_stack env sigma x []) @@ -879,19 +913,21 @@ and eqappr cv_pb infos appr1 appr2 = | None -> fun _ -> raise NotConvertible) (* other constructors *) - | (FOP2(Lambda,c1,c2), FOP2(Lambda,c'1,c'2)) -> + | (FLam (_,c1,c2,_,_), FLam (_,c'1,c'2,_,_)) -> bool_and_convert (Array.length v1 = 0 && Array.length v2 = 0) (convert_and (ccnv (pb_equal cv_pb) infos el1 el2 c1 c'1) - (ccnv (pb_equal cv_pb) infos el1 el2 c2 c'2)) + (ccnv (pb_equal cv_pb) infos (el_lift el1) (el_lift el2) c2 c'2)) + + | (FLet _, _) | (_, FLet _) -> anomaly "Normally removed by fhnf" - | (FOP2(Prod,c1,c2), FOP2(Prod,c'1,c'2)) -> + | (FPrd (_,c1,c2,_,_), FPrd (_,c'1,c'2,_,_)) -> bool_and_convert (Array.length v1 = 0 && Array.length v2 = 0) (convert_and (ccnv (pb_equal cv_pb) infos el1 el2 c1 c'1) (* Luo's system *) - (ccnv cv_pb infos el1 el2 c2 c'2)) + (ccnv cv_pb infos (el_lift el1) (el_lift el2) c2 c'2)) (* Inductive types: MutInd MutConstruct MutCase Fix Cofix *) @@ -926,8 +962,8 @@ and eqappr cv_pb infos appr1 appr2 = let fconv cv_pb env sigma t1 t2 = - let t1 = strong (fun _ _ -> strip_outer_cast) env sigma t1 - and t2 = strong (fun _ _ -> strip_outer_cast) env sigma t2 in + let t1 = local_strong strip_outer_cast t1 + and t2 = local_strong strip_outer_cast t2 in if eq_constr t1 t2 then Constraint.empty else @@ -972,9 +1008,11 @@ let plain_instance s c = | DOP1(oper,c) -> DOP1(oper, irec c) | DOP2(oper,c1,c2) -> DOP2(oper, irec c1, irec c2) | DOPN(oper,cl) -> DOPN(oper, Array.map irec cl) - | DOPL(oper,cl) -> DOPL(oper, List.map irec cl) | DLAM(x,c) -> DLAM(x, irec c) | DLAMV(x,v) -> DLAMV(x, Array.map irec v) + | CLam (n,t,c) -> CLam (n, typed_app irec t, irec c) + | CPrd (n,t,c) -> CPrd (n, typed_app irec t, irec c) + | CLet (n,b,t,c) -> CLet (n, irec b, typed_app irec t, irec c) | u -> u in if s = [] then c else irec c @@ -992,7 +1030,7 @@ let instance s c = let hnf_prod_app env sigma t n = match whd_betadeltaiota env sigma t with - | DOP2(Prod,_,DLAM(_,b)) -> subst1 n b + | CPrd (_,_,b) -> subst1 n b | _ -> anomaly "hnf_prod_app: Need a product" let hnf_prod_appvect env sigma t nl = @@ -1003,7 +1041,7 @@ let hnf_prod_applist env sigma t nl = let hnf_lam_app env sigma t n = match whd_betadeltaiota env sigma t with - | DOP2(Lambda,_,DLAM(_,b)) -> subst1 n b + | CLam (_,_,b) -> subst1 n b | _ -> anomaly "hnf_lam_app: Need an abstraction" let hnf_lam_appvect env sigma t nl = @@ -1015,7 +1053,7 @@ let hnf_lam_applist env sigma t nl = let splay_prod env sigma = let rec decrec m c = match whd_betadeltaiota env sigma c with - | DOP2(Prod,a,DLAM(n,c_0)) -> decrec ((n,a)::m) c_0 + | CPrd (n,a,c0) -> decrec ((n,body_of_type a)::m) c0 | t -> m,t in decrec [] @@ -1030,8 +1068,8 @@ let sort_of_arity env c = snd (splay_arity env Evd.empty c) let decomp_n_prod env sigma n = let rec decrec m ln c = if m = 0 then (ln,c) else match whd_betadeltaiota env sigma c with - | DOP2(Prod,a,DLAM(n,c0)) -> - decrec (m-1) (Sign.add_rel_decl (n,outcast_type a) ln) c0 + | CPrd (n,a,c0) -> + decrec (m-1) (Sign.add_rel_decl (n,a) ln) c0 | _ -> error "decomp_n_prod: Not enough products" in decrec n Sign.empty_rel_context @@ -1053,7 +1091,7 @@ with bj=aj if j<>ik and bj=(Rel c) and Bic=Aic[xn..xic-1 <- an..aic-1] let compute_consteval env sigma c = let rec srec n labs c = match whd_betadeltaeta_stack env sigma c [] with - | (DOP2(Lambda,t,DLAM(_,g)),[]) -> srec (n+1) (t::labs) g + | CLam (_,t,g), [] -> srec (n+1) (t::labs) g | (DOPN(Fix((nv,i)),bodies),l) -> if List.length l > n then raise Elimconst @@ -1083,22 +1121,23 @@ let compute_consteval env sigma c = (* One step of approximation *) let rec apprec env sigma c stack = - let (t,stack) = whd_betaiota_stack c stack in - match t with - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase t in + let (t, stack as s) = whd_betaiota_stack c stack in + match kind_of_term t with + | IsMutCase (ci,p,d,lf) -> let (cr,crargs) = whd_betadeltaiota_stack env sigma d [] in let rslt = mkMutCaseA ci p (applist(cr,crargs)) lf in if reducible_mind_case cr then apprec env sigma rslt stack else - (t,stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = - reduce_fix (whd_betadeltaiota_stack env sigma) t stack - in - if reduced then apprec env sigma fix stack else (fix,stack) - | _ -> (t,stack) + s + | IsFix fix -> + (match reduce_fix + (fun (c,l) -> whd_betadeltaiota_stack env sigma c l) + fix stack + with + | Reduced (c,stack) -> apprec env sigma c stack + | NotReducible -> s) + | _ -> s let hnf env sigma c = apprec env sigma c [] @@ -1108,36 +1147,31 @@ let hnf env sigma c = apprec env sigma c [] * Used in Programs. * Added by JCF, 29/1/98. *) -let whd_programs_stack env sigma = - let rec whrec x stack = - match x with - | DOPN(AppL,cl) -> - if occur_meta cl.(1) then - (x,stack) - else - whrec (array_hd cl) (array_app_tl cl stack) - | DOP2(Lambda,_,DLAM(_,c)) -> +let whd_programs_stack env sigma x l = + let rec whrec (x, stack as s) = + match kind_of_term x with + | IsAppL (f,[c]) -> if occur_meta c then s else whrec (f, c::stack) + | IsLambda (_,_,c) -> (match stack with - | [] -> (x,stack) + | [] -> s | (a::m) -> stacklam whrec [a] c m) - | DOPN(MutCase _,_) -> - let (ci,p,d,lf) = destCase x in + | IsMutCase (ci,p,d,lf) -> if occur_meta d then - (x,stack) + s else - let (c,cargs) = whrec d [] in + let (c,cargs) = whrec (d, []) in if reducible_mind_case c then whrec (reduce_mind_case - {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}) - stack + {mP=p; mconstr=c; mcargs=cargs; mci=ci; mlf=lf}, stack) else (mkMutCaseA ci p (applist(c,cargs)) lf, stack) - | DOPN(Fix _,_) -> - let (reduced,(fix,stack)) = reduce_fix whrec x stack in - if reduced then whrec fix stack else (fix,stack) - | x -> (x,stack) + | IsFix fix -> + (match reduce_fix whrec fix stack with + | Reduced s' -> whrec s' + | NotReducible -> s) + | _ -> s in - whrec + whrec (x, l) let whd_programs env sigma x = applist (whd_programs_stack env sigma x []) @@ -1145,37 +1179,34 @@ exception IsType let is_arity env sigma = let rec srec c = - match whd_betadeltaiota env sigma c with - | DOP0(Sort _) -> true - | DOP2(Prod,_,DLAM(_,c')) -> srec c' - | DOP2(Lambda,_,DLAM(_,c')) -> srec c' + match kind_of_term (whd_betadeltaiota env sigma c) with + | IsSort _ -> true + | IsProd (_,_,c') -> srec c' + | IsLambda (_,_,c') -> srec c' | _ -> false in srec let info_arity env sigma = let rec srec c = - match whd_betadeltaiota env sigma c with - | DOP0(Sort(Prop Null)) -> false - | DOP0(Sort(Prop Pos)) -> true - | DOP2(Prod,_,DLAM(_,c')) -> srec c' - | DOP2(Lambda,_,DLAM(_,c')) -> srec c' + match kind_of_term (whd_betadeltaiota env sigma c) with + | IsSort (Prop Null) -> false + | IsSort (Prop Pos) -> true + | IsProd (_,_,c') -> srec c' + | IsLambda (_,_,c') -> srec c' | _ -> raise IsType in srec -let is_logic_arity env sigma c = - try (not (info_arity env sigma c)) with IsType -> false - -let is_info_arity env sigma c = +let is_info_arity env sigma c = try (info_arity env sigma c) with IsType -> true - + let is_type_arity env sigma = let rec srec c = - match whd_betadeltaiota env sigma c with - | DOP0(Sort(Type _)) -> true - | DOP2(Prod,_,DLAM(_,c')) -> srec c' - | DOP2(Lambda,_,DLAM(_,c')) -> srec c' + match kind_of_term (whd_betadeltaiota env sigma c) with + | IsSort (Type _) -> true + | IsProd (_,_,c') -> srec c' + | IsLambda (_,_,c') -> srec c' | _ -> false in srec @@ -1186,20 +1217,6 @@ let is_info_type env sigma t = (s <> Prop Null && try info_arity env sigma t.utj_val with IsType -> true) -(* Pour l'extraction -let is_info_cast_type env sigma c = - match c with - | DOP2(Cast,c,t) -> - (try info_arity env sigma t - with IsType -> try info_arity env sigma c with IsType -> true) - | _ -> try info_arity env sigma c with IsType -> true - -let contents_of_cast_type env sigma c = - if is_info_cast_type env sigma c then Pos else Null -*) - -let is_info_sort = is_info_arity - (* calcul des arguments implicites *) (* la seconde liste est ordonne'e *) @@ -1211,31 +1228,36 @@ let ord_add x l = in aux l -let add_free_rels_until depth m acc = - let rec frec depth loc acc = function +let add_free_rels_until bound m acc = + let rec frec depth acc = function | Rel n -> - if (n <= depth) & (n > loc) then (ord_add (depth-n+1) acc) else acc - | DOPN(_,cl) -> Array.fold_left (frec depth loc) acc cl - | DOPL(_,cl) -> List.fold_left (frec depth loc) acc cl - | DOP2(_,c1,c2) -> frec depth loc (frec depth loc acc c1) c2 - | DOP1(_,c) -> frec depth loc acc c - | DLAM(_,c) -> frec (depth+1) (loc+1) acc c - | DLAMV(_,cl) -> Array.fold_left (frec (depth+1) (loc+1)) acc cl + if (n < bound+depth) & (n >= depth) then + Intset.add (bound+depth-n) acc + else + acc + | DOPN(_,cl) -> Array.fold_left (frec depth) acc cl + | DOP2(_,c1,c2) -> frec depth (frec depth acc c1) c2 + | DOP1(_,c) -> frec depth acc c + | DLAM(_,c) -> frec (depth+1) acc c + | DLAMV(_,cl) -> Array.fold_left (frec (depth+1)) acc cl + | CLam (_,t,c) -> frec (depth+1) (frec depth acc (body_of_type t)) c + | CPrd (_,t,c) -> frec (depth+1) (frec depth acc (body_of_type t)) c + | CLet (_,b,t,c) -> frec (depth+1) (frec depth (frec depth acc b) (body_of_type t)) c | VAR _ -> acc | DOP0 _ -> acc in - frec depth 0 acc m + frec 1 acc m (* calcule la liste des arguments implicites *) let poly_args env sigma t = - let rec aux n t = match (whd_betadeltaiota env sigma t) with - | DOP2(Prod,a,DLAM(_,b)) -> add_free_rels_until n a (aux (n+1) b) - | DOP2(Cast,t',_) -> aux n t' - | _ -> [] + let rec aux n t = match kind_of_term (whd_betadeltaiota env sigma t) with + | IsProd (_,a,b) -> add_free_rels_until n a (aux (n+1) b) + | IsCast (t',_) -> aux n t' + | _ -> Intset.empty in - match (strip_outer_cast (whd_betadeltaiota env sigma t)) with - | DOP2(Prod,a,DLAM(_,b)) -> aux 1 b + match kind_of_term (strip_outer_cast (whd_betadeltaiota env sigma t)) with + | IsProd (_,a,b) -> Intset.elements (aux 1 b) | _ -> [] diff --git a/kernel/reduction.mli b/kernel/reduction.mli index bab5f446f..01d42fc07 100644 --- a/kernel/reduction.mli +++ b/kernel/reduction.mli @@ -3,7 +3,7 @@ (*i*) open Names -open Generic +(*i open Generic i*) open Term open Univ open Evd @@ -35,10 +35,10 @@ val under_casts : 'a contextual_reduction_function -> 'a contextual_reduction_function val strong : 'a reduction_function -> 'a reduction_function val local_strong : local_reduction_function -> local_reduction_function -val strong_prodspine : 'a reduction_function -> 'a reduction_function +val strong_prodspine : local_reduction_function -> local_reduction_function val stack_reduction_of_reduction : 'a reduction_function -> 'a stack_reduction_function -val stacklam : (constr -> constr list -> 'a) -> constr list -> constr +val stacklam : (constr * constr list -> 'a) -> constr list -> constr -> constr list -> 'a (*s Generic Optimized Reduction Functions using Closures *) @@ -110,15 +110,14 @@ val reducible_mind_case : constr -> bool val reduce_mind_case : constr miota_args -> constr val is_arity : env -> 'a evar_map -> constr -> bool -val is_info_arity : env -> 'a evar_map -> constr -> bool -val is_info_sort : env -> 'a evar_map -> constr -> bool -val is_logic_arity : env -> 'a evar_map -> constr -> bool -val is_type_arity : env -> 'a evar_map -> constr -> bool val is_info_type : env -> 'a evar_map -> unsafe_type_judgment -> bool +val is_info_arity : env -> 'a evar_map -> constr -> bool (*i Pour l'extraction +val is_type_arity : env -> 'a evar_map -> constr -> bool val is_info_cast_type : env -> 'a evar_map -> constr -> bool val contents_of_cast_type : env -> 'a evar_map -> constr -> contents i*) + val poly_args : env -> 'a evar_map -> constr -> int list val whd_programs : 'a reduction_function @@ -130,9 +129,12 @@ val fold_commands : constr list -> 'a reduction_function val pattern_occs : (int list * constr * constr) list -> 'a reduction_function val compute : 'a reduction_function +(* [reduce_fix] contracts a fix redex if it is actually reducible *) +type fix_reduction_result = NotReducible | Reduced of (constr * constr list) + val fix_recarg : fixpoint -> 'a list -> (int * 'a) option -val reduce_fix : (constr -> 'a list -> constr * constr list) -> constr -> - constr list -> bool * (constr * constr list) +val reduce_fix : (constr * constr list -> constr * constr list) -> fixpoint -> + constr list -> fix_reduction_result (*s Conversion Functions (uses closures, lazy strategy) *) diff --git a/kernel/safe_typing.ml b/kernel/safe_typing.ml index ca5d4a2ec..6b97c63ac 100644 --- a/kernel/safe_typing.ml +++ b/kernel/safe_typing.ml @@ -5,7 +5,7 @@ open Pp open Util open Names open Univ -open Generic +(*i open Generic i*) open Term open Reduction open Sign @@ -122,6 +122,16 @@ let rec execute mf env cstr = let (j,cst3) = gen_rel env1 Evd.empty name varj j' in let cst = Constraint.union cst1 (Constraint.union cst2 cst3) in (j, cst) + + | IsLetIn (name,c1,c2,c3) -> + let (j1,cst1) = execute mf env c1 in + let (j2,cst2) = execute mf env c2 in + let { uj_val = b; uj_type = t } = cast_rel env Evd.empty j1 j2 in + let (j3,cst3) = execute mf (push_rel_def (name,b,t) env) c3 in + let cst = Constraint.union cst1 (Constraint.union cst2 cst3) in + ({ uj_val = mkLetIn (name, j1.uj_val, j2.uj_val, j3.uj_val) ; + uj_type = typed_app (subst1 j1.uj_val) j3.uj_type }, + cst) | IsCast (c,t) -> let (cj,cst1) = execute mf env c in diff --git a/kernel/sign.ml b/kernel/sign.ml index edee43885..eac5c8cc9 100644 --- a/kernel/sign.ml +++ b/kernel/sign.ml @@ -3,7 +3,7 @@ open Names open Util -open Generic +(*i open Generic i*) open Term (* Signatures *) @@ -98,7 +98,7 @@ let map_rel_context = map let instantiate_sign sign args = let rec instrec = function | ((id,None,_) :: sign, c::args) -> (id,c) :: (instrec (sign,args)) - | ((id,Some c,_) :: _, args) -> (id,c) :: (instrec (sign,args)) + | ((id,Some c,_) :: sign, args) -> (id,c) :: (instrec (sign,args)) | ([],[]) -> [] | ([],_) | (_,[]) -> anomaly "Signature and its instance do not match" @@ -146,26 +146,24 @@ let empty_names_context = [] (* Transforms a product term (x1:T1)..(xn:Tn)T into the pair ([(xn,Tn);...;(x1,T1)],T), where T is not a product *) let decompose_prod_assum = - let rec prodec_rec l = function - | DOP2(Prod,t,DLAM(x,c)) -> - prodec_rec (add_rel_decl (x,outcast_type t) l) c -(* | Letin,t,DLAM(x,c)) -> - prodec_rec (add_rel_def (x,c,outcast_type t) l) c*) - | DOP2(Cast,c,_) -> prodec_rec l c - | c -> l,c + let rec prodec_rec l c = + match kind_of_term c with + | IsProd (x,t,c) -> prodec_rec (add_rel_decl (x,outcast_type t) l) c + | IsLetIn (x,b,t,c) -> prodec_rec (add_rel_def (x,b,outcast_type t) l) c + | IsCast (c,_) -> prodec_rec l c + | _ -> l,c in prodec_rec empty_rel_context (* Transforms a lambda term [x1:T1]..[xn:Tn]T into the pair ([(xn,Tn);...;(x1,T1)],T), where T is not a lambda *) let decompose_lam_assum = - let rec lamdec_rec l = function - | DOP2(Lambda,t,DLAM(x,c)) -> - lamdec_rec (add_rel_decl (x,outcast_type t) l) c -(* | Letin,t,DLAM(x,c)) -> - lamdec_rec (add_rel_def (x,c,outcast_type t) l) c*) - | DOP2(Cast,c,_) -> lamdec_rec l c - | c -> l,c + let rec lamdec_rec l c = + match kind_of_term c with + | IsLambda (x,t,c) -> lamdec_rec (add_rel_decl (x,outcast_type t) l) c + | IsLetIn (x,b,t,c) -> lamdec_rec (add_rel_def (x,b,outcast_type t) l) c + | IsCast (c,_) -> lamdec_rec l c + | _ -> l,c in lamdec_rec empty_rel_context @@ -175,10 +173,12 @@ let decompose_prod_n_assum n = if n < 0 then error "decompose_prod_n: integer parameter must be positive"; let rec prodec_rec l n c = if n=0 then l,c - else match c with - | DOP2(Prod,t,DLAM(x,c)) -> prodec_rec (add_rel_decl (x,outcast_type t) l) (n-1) c - | DOP2(Cast,c,_) -> prodec_rec l n c - | c -> error "decompose_prod_n: not enough products" + else match kind_of_term c with + | IsProd (x,t,c) -> prodec_rec (add_rel_decl(x,outcast_type t) l) (n-1) c + | IsLetIn (x,b,t,c) -> + prodec_rec (add_rel_def (x,b,outcast_type t) l) (n-1) c + | IsCast (c,_) -> prodec_rec l n c + | c -> error "decompose_prod_n: not enough products" in prodec_rec empty_rel_context n @@ -188,10 +188,11 @@ let decompose_lam_n_assum n = if n < 0 then error "decompose_lam_n: integer parameter must be positive"; let rec lamdec_rec l n c = if n=0 then l,c - else match c with - | DOP2(Lambda,t,DLAM(x,c)) -> lamdec_rec (add_rel_decl (x,outcast_type t) l) (n-1) c - | DOP2(Cast,c,_) -> lamdec_rec l n c - | c -> error "decompose_lam_n: not enough abstractions" + else match kind_of_term c with + | IsLambda (x,t,c) -> lamdec_rec (add_rel_decl (x,outcast_type t) l) (n-1) c + | IsLetIn (x,b,t,c) -> + lamdec_rec (add_rel_def (x,b,outcast_type t) l) (n-1) c + | IsCast (c,_) -> lamdec_rec l n c + | c -> error "decompose_lam_n: not enough abstractions" in lamdec_rec empty_rel_context n - diff --git a/kernel/sign.mli b/kernel/sign.mli index 17d9267d9..889c79b4e 100644 --- a/kernel/sign.mli +++ b/kernel/sign.mli @@ -3,7 +3,7 @@ (*i*) open Names -open Generic +(*i open Generic i*) open Term (*i*) diff --git a/kernel/sosub.ml b/kernel/sosub.ml index 904d089d3..7212216ee 100644 --- a/kernel/sosub.ml +++ b/kernel/sosub.ml @@ -3,9 +3,9 @@ open Util open Names -open Generic +(*i open Generic i*) open Term - +(* (* Given a term with variables in it, and second-order substitution, this function will apply the substitution. The special operator "XTRA[$SOAPP]" is used to represent the second-order @@ -100,15 +100,6 @@ let propagate_names = cllist (smap,[]) in (smap',DOPN(op,Array.of_list cl'list)) - | DOPL(op,cl) -> - let cllist = cl in - let (smap',cl'list) = - List.fold_right - (fun c (smap,acc) -> - let (smap',c') = proprec smap c in (smap',c'::acc)) - cllist (smap,[]) - in - (smap',DOPL(op,cl'list)) | DLAM(na,c) -> let (lna', c') = proprec (na::smap) c in (List.tl lna', DLAM(List.hd lna', c')) @@ -163,14 +154,6 @@ let rec soeval t= socontract args lam else DOPN(op,cl') - | DOPL(op,cl) -> - let cl' = List.map soeval cl in - if is_soapp_operator t then - let lam = List.hd cl' - and args = List.tl cl' in - socontract args lam - else - DOPL(op,cl') let rec try_soeval t = match t with @@ -197,15 +180,6 @@ let rec try_soeval t = with (Failure _ | UserError _) -> DOPN(op,cl')) else DOPN(op,cl') - | DOPL(op,cl) -> - let cl' = List.map try_soeval cl in - if is_soapp_operator t then - let lam = List.hd cl' - and args = List.tl cl' in - (try socontract args lam - with (Failure _ | UserError _) -> DOPL(op,cl')) - else - DOPL(op,cl') let soexecute t = let (_,t) = propagate_names [] t in @@ -217,3 +191,7 @@ let try_soexecute t = with (Failure _ | UserError _) -> ([],t) in try_soeval t +*) + +let soexecute a = failwith "No longer implemented" + diff --git a/kernel/sosub.mli b/kernel/sosub.mli index 531b7ee7e..123362527 100644 --- a/kernel/sosub.mli +++ b/kernel/sosub.mli @@ -8,5 +8,7 @@ open Term (* Second-order substitutions. *) val soexecute : constr -> constr +(* val try_soexecute : constr -> constr +*) diff --git a/kernel/term.ml b/kernel/term.ml index f4c074471..40feeaab1 100644 --- a/kernel/term.ml +++ b/kernel/term.ml @@ -6,7 +6,6 @@ open Util open Pp open Names -open Generic open Univ (* Coq abstract syntax with deBruijn variables; 'a is the type of sorts *) @@ -64,14 +63,34 @@ let print_sort = function | Prop Null -> [< 'sTR "Prop" >] | Type _ -> [< 'sTR "Type" >] -type constr = sorts oper term +(********************************************************************) +(* Generic syntax of terms with de Bruijn indexes *) +(********************************************************************) + +type constr = + | DOP0 of sorts oper (* atomic terms *) + | DOP1 of sorts oper * constr (* operator of arity 1 *) + | DOP2 of sorts oper * constr * constr (* operator of arity 2 *) + | DOPN of sorts oper * constr array (* operator of variadic arity *) + | DLAM of name * constr (* deBruijn binder on one term *) + | DLAMV of name * constr array (* deBruijn binder on many terms *) + | CLam of name * constr * constr + | CPrd of name * constr * constr + | CLet of name * constr * constr * constr + | VAR of identifier (* named variable *) + | Rel of int (* variable as deBruijn index *) + +and + (* + typed_type = sorts judge + *) + typed_type = constr type flat_arity = (name * constr) list * sorts type 'a judge = { body : constr; typ : 'a } (* -type typed_type = sorts judge type typed_term = typed_type judge let make_typed t s = { body = t; typ = s } @@ -91,7 +110,6 @@ let outcast_type = function let typed_combine f g t u = { f t.body u.body ; g t.typ u.typ} *) -type typed_type = constr type typed_term = typed_type judge let make_typed t s = t @@ -115,15 +133,281 @@ type rel_declaration = name * constr option * typed_type (****************************************************************************) (*********************) +(* Occurring *) +(*********************) + +exception FreeVar +exception Occur + +(* (closedn n M) raises FreeVar if a variable of height greater than n + occurs in M, returns () otherwise *) + +let closedn = + let rec closed_rec n = function + | Rel(m) -> if m>n then raise FreeVar + | VAR _ -> () + | DOPN(_,cl) -> Array.iter (closed_rec n) cl + | DOP2(_,c1,c2) -> closed_rec n c1; closed_rec n c2 + | DOP1(_,c) -> closed_rec n c + | DLAM(_,c) -> closed_rec (n+1) c + | DLAMV(_,v) -> Array.iter (closed_rec (n+1)) v + | CLam (_,t,c) -> closed_rec n t; closed_rec (n+1) c + | CPrd (_,t,c) -> closed_rec n t; closed_rec (n+1) c + | CLet (_,b,t,c) -> closed_rec n b; closed_rec n t; closed_rec (n+1) c + | _ -> () + in + closed_rec + +(* [closed0 M] is true iff [M] is a (deBruijn) closed term *) + +let closed0 term = + try closedn 0 term; true with FreeVar -> false + +(* returns the list of free debruijn indices in a term *) + +let free_rels m = + let rec frec depth acc = function + | Rel n -> if n >= depth then Intset.add (n-depth+1) acc else acc + | DOPN(_,cl) -> Array.fold_left (frec depth) acc cl + | DOP2(_,c1,c2) -> frec depth (frec depth acc c1) c2 + | DOP1(_,c) -> frec depth acc c + | DLAM(_,c) -> frec (depth+1) acc c + | DLAMV(_,cl) -> Array.fold_left (frec (depth+1)) acc cl + | CLam (_,t,c) -> frec (depth+1) (frec depth acc t) c + | CPrd (_,t,c) -> frec (depth+1) (frec depth acc t) c + | CLet (_,b,t,c) -> frec (depth+1) (frec depth (frec depth acc b) t) c + | VAR _ -> acc + | DOP0 _ -> acc + in + frec 1 Intset.empty m + +(* (noccurn n M) returns true iff (Rel n) does NOT occur in term M *) + +let noccurn n term = + let rec occur_rec n = function + | Rel(m) -> if m = n then raise Occur + | VAR _ -> () + | DOPN(_,cl) -> Array.iter (occur_rec n) cl + | DOP1(_,c) -> occur_rec n c + | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2 + | DLAM(_,c) -> occur_rec (n+1) c + | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v + | CLam (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CPrd (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CLet (_,b,t,c) -> occur_rec n b; occur_rec n t; occur_rec (n+1) c + | _ -> () + in + try occur_rec n term; true with Occur -> false + +(* (noccur_between n m M) returns true iff (Rel p) does NOT occur in term M + for n <= p < n+m *) + +let noccur_between n m term = + let rec occur_rec n = function + | Rel(p) -> if n<=p && p<n+m then raise Occur + | VAR _ -> () + | DOPN(_,cl) -> Array.iter (occur_rec n) cl + | DOP1(_,c) -> occur_rec n c + | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2 + | DLAM(_,c) -> occur_rec (n+1) c + | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v + | CLam (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CPrd (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CLet (_,b,t,c) -> occur_rec n b; occur_rec n t; occur_rec (n+1) c + | _ -> () + in + try occur_rec n term; true with Occur -> false + +(* Checking function for terms containing existential variables. + The function [noccur_with_meta] considers the fact that + each existential variable (as well as each isevar) + in the term appears applied to its local context, + which may contain the CoFix variables. These occurrences of CoFix variables + are not considered *) + +let noccur_with_meta n m term = + let rec occur_rec n = function + | Rel p -> if n<=p & p<n+m then raise Occur + | VAR _ -> () + | DOPN(AppL,cl) -> + (match cl.(0) with + | DOP2 (Cast,DOP0 (Meta _),_) -> () + | DOP0 (Meta _) -> () + | _ -> Array.iter (occur_rec n) cl) + | DOPN(Evar _, _) -> () + | DOPN(op,cl) -> Array.iter (occur_rec n) cl + | DOP0(_) -> () + | DOP1(_,c) -> occur_rec n c + | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2 + | DLAM(_,c) -> occur_rec (n+1) c + | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v + | CLam (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CPrd (_,t,c) -> occur_rec n t; occur_rec (n+1) c + | CLet (_,b,t,c) -> occur_rec n b; occur_rec n t; occur_rec (n+1) c + in + try (occur_rec n term; true) with Occur -> false + + +(*********************) +(* Lifting *) +(*********************) + +(* Explicit lifts and basic operations *) +type lift_spec = + | ELID + | ELSHFT of lift_spec * int (* ELSHFT(l,n) == lift of n, then apply lift l *) + | ELLFT of int * lift_spec (* ELLFT(n,l) == apply l to de Bruijn > n *) + (* i.e under n binders *) + +(* compose a relocation of magnitude n *) +let rec el_shft n = function + | ELSHFT(el,k) -> el_shft (k+n) el + | el -> if n = 0 then el else ELSHFT(el,n) + + +(* cross n binders *) +let rec el_liftn n = function + | ELID -> ELID + | ELLFT(k,el) -> el_liftn (n+k) el + | el -> if n=0 then el else ELLFT(n, el) + +let el_lift el = el_liftn 1 el + +(* relocation of de Bruijn n in an explicit lift *) +let rec reloc_rel n = function + | ELID -> n + | ELLFT(k,el) -> + if n <= k then n else (reloc_rel (n-k) el) + k + | ELSHFT(el,k) -> (reloc_rel (n+k) el) + + +(* The generic lifting function *) +let rec exliftn el = function + | Rel i -> Rel(reloc_rel i el) + | DOPN(oper,cl) -> DOPN(oper, Array.map (exliftn el) cl) + | DOP1(oper,c) -> DOP1(oper, exliftn el c) + | DOP2(oper,c1,c2) -> DOP2(oper, exliftn el c1, exliftn el c2) + | DLAM(na,c) -> DLAM(na, exliftn (el_lift el) c) + | DLAMV(na,v) -> DLAMV(na, Array.map (exliftn (el_lift el)) v) + | CLam (n,t,c) -> CLam (n, exliftn el t, exliftn (el_lift el) c) + | CPrd (n,t,c) -> CPrd (n, exliftn el t, exliftn (el_lift el) c) + | CLet (n,b,t,c) -> CLet (n,exliftn el b,exliftn el t,exliftn (el_lift el) c) + | x -> x + +(* Lifting the binding depth across k bindings *) + +let liftn k n = + match el_liftn (pred n) (el_shft k ELID) with + | ELID -> (fun c -> c) + | el -> exliftn el + +let lift k = liftn k 1 + +let pop t = lift (-1) t + +let lift_context n l = + let k = List.length l in + list_map_i (fun i (name,c) -> (name,liftn n (k-i) c)) 0 l + +(*********************) +(* Substituting *) +(*********************) + +(* (subst1 M c) substitutes M for Rel(1) in c + we generalise it to (substl [M1,...,Mn] c) which substitutes in parallel + M1,...,Mn for respectively Rel(1),...,Rel(n) in c *) + +(* 1st : general case *) + +type info = Closed | Open | Unknown +type 'a substituend = { mutable sinfo: info; sit: 'a } + +let rec lift_substituend depth s = + match s.sinfo with + | Closed -> s.sit + | Open -> lift depth s.sit + | Unknown -> + s.sinfo <- if closed0 s.sit then Closed else Open; + lift_substituend depth s + +let make_substituend c = { sinfo=Unknown; sit=c } + +let substn_many lamv n = + let lv = Array.length lamv in + let rec substrec depth = function + | Rel k as x -> + if k<=depth then + x + else if k-depth <= lv then + lift_substituend depth lamv.(k-depth-1) + else + Rel (k-lv) + | VAR id -> VAR id + | DOPN(oper,cl) -> DOPN(oper,Array.map (substrec depth) cl) + | DOP1(oper,c) -> DOP1(oper,substrec depth c) + | DOP2(oper,c1,c2) -> DOP2(oper,substrec depth c1,substrec depth c2) + | DLAM(na,c) -> DLAM(na,substrec (depth+1) c) + | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (depth+1)) v) + | CLam (n,t,c) -> CLam (n, substrec depth t, substrec (depth+1) c) + | CPrd (n,t,c) -> CPrd (n, substrec depth t, substrec (depth+1) c) + | CLet (n,b,t,c) -> CLet (n, substrec depth b, substrec depth t, + substrec (depth+1) c) + | x -> x + in + substrec n + +let substnl laml k = + substn_many (Array.map make_substituend (Array.of_list laml)) k +let substl laml = + substn_many (Array.map make_substituend (Array.of_list laml)) 0 +let subst1 lam = substl [lam] + +(* (thin_val sigma) removes identity substitutions from sigma *) + +let rec thin_val = function + | [] -> [] + | (((id,{sit=VAR id'}) as s)::tl) -> + if id = id' then thin_val tl else s::(thin_val tl) + | h::tl -> h::(thin_val tl) + +(* (replace_vars sigma M) applies substitution sigma to term M *) +let replace_vars var_alist = + let var_alist = + List.map (fun (str,c) -> (str,make_substituend c)) var_alist in + let var_alist = thin_val var_alist in + let rec substrec n = function + | (VAR(x) as c) -> + (try lift_substituend n (List.assoc x var_alist) + with Not_found -> c) + + | DOPN(oper,cl) -> DOPN(oper,Array.map (substrec n) cl) + | DOP1(oper,c) -> DOP1(oper,substrec n c) + | DOP2(oper,c1,c2) -> DOP2(oper,substrec n c1,substrec n c2) + | DLAM(na,c) -> DLAM(na,substrec (n+1) c) + | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (n+1)) v) + | CLam (na,t,c) -> CLam (na, substrec n t, substrec (n+1) c) + | CPrd (na,t,c) -> CPrd (na, substrec n t, substrec (n+1) c) + | CLet (na,b,t,c) -> CLet (na,substrec n b,substrec n t,substrec (n+1) c) + | x -> x + in + if var_alist = [] then (function x -> x) else substrec 0 + +(* (subst_var str t) substitute (VAR str) by (Rel 1) in t *) +let subst_var str = replace_vars [(str, Rel 1)] + +(* (subst_vars [id1;...;idn] t) substitute (VAR idj) by (Rel j) in t *) +let subst_vars vars = + let _,subst = + List.fold_left (fun (n,l) var -> ((n+1),(var,Rel n)::l)) (1,[]) vars + in replace_vars (List.rev subst) + +(*********************) (* Term constructors *) (*********************) (* Constructs a DeBrujin index with number n *) let mkRel n = (Rel n) -(* Constructs an existential variable named "?" *) -let mkExistential = (DOP0 (XTRA "ISEVAR")) - (* Constructs an existential variable named "?n" *) let mkMeta n = DOP0 (Meta n) @@ -155,30 +439,30 @@ let mkImplicit = DOP0 (Sort implicit_sort) (* Constructs the term t1::t2, i.e. the term t1 casted with the type t2 *) (* (that means t2 is declared as the type of t1) *) -let mkCast t1 t2 = +let mkCast (t1,t2) = match t1 with | DOP2(Cast,t,_) -> DOP2(Cast,t,t2) | _ -> (DOP2 (Cast,t1,t2)) (* Constructs the product (x:t1)t2 *) -let mkProd x t1 t2 = (DOP2 (Prod,t1,(DLAM (x,t2)))) -let mkNamedProd id typ c = mkProd (Name id) typ (subst_var id c) -let mkProd_string s t c = mkProd (Name (id_of_string s)) t c +let mkProd (x,t1,t2) = CPrd (x,t1,t2) +let mkNamedProd id typ c = mkProd (Name id, typ, subst_var id c) +let mkProd_string s t c = mkProd (Name (id_of_string s), t, c) (* Constructs the abstraction [x:t1]t2 *) -let mkLambda x t1 t2 = (DOP2 (Lambda,t1,(DLAM (x,t2)))) -let mkNamedLambda id typ c = mkLambda (Name id) typ (subst_var id c) -let mkLambda_string s t c = mkLambda (Name (id_of_string s)) t c +let mkLambda (x,t1,t2) = CLam (x,t1,t2) +let mkNamedLambda id typ c = mkLambda (Name id, typ, subst_var id c) +let mkLambda_string s t c = mkLambda (Name (id_of_string s), t, c) (* Constructs [x=c_1:t]c_2 *) -let mkLetIn x c1 t c2 = failwith "TODO" -let mkNamedLetIn id c1 t c2 = mkLetIn (Name id) c1 t (subst_var id c2) +let mkLetIn (x,c1,t,c2) = CLet (x,c1,t,c2) +let mkNamedLetIn id c1 t c2 = mkLetIn (Name id, c1, t, subst_var id c2) (* Constructs either [(x:t)c] or [[x=b:t]c] *) let mkProd_or_LetIn (na,body,t) c = match body with - | None -> mkProd na t c - | Some b -> mkLetIn na b t c + | None -> mkProd (na, t, c) + | Some b -> mkLetIn (na, b, t, c) let mkNamedProd_or_LetIn (id,body,t) c = match body with @@ -188,8 +472,8 @@ let mkNamedProd_or_LetIn (id,body,t) c = (* Constructs either [[x:t]c] or [[x=b:t]c] *) let mkLambda_or_LetIn (na,body,t) c = match body with - | None -> mkLambda na t c - | Some b -> mkLetIn na b t c + | None -> mkLambda (na, t, c) + | Some b -> mkLetIn (na, b, t, c) let mkNamedLambda_or_LetIn (id,body,t) c = match body with @@ -199,7 +483,7 @@ let mkNamedLambda_or_LetIn (id,body,t) c = (* Constructs either [(x:t)c] or [c] where [x] is replaced by [b] *) let mkProd_wo_LetIn (na,body,t) c = match body with - | None -> mkProd na (body_of_type t) c + | None -> mkProd (na, body_of_type t, c) | Some b -> subst1 b c let mkNamedProd_wo_LetIn (id,body,t) c = @@ -208,7 +492,7 @@ let mkNamedProd_wo_LetIn (id,body,t) c = | Some b -> subst1 b (subst_var id c) (* non-dependent product t1 -> t2 *) -let mkArrow t1 t2 = mkProd Anonymous t1 t2 +let mkArrow t1 t2 = mkProd (Anonymous, t1, t2) (* If lt = [t1; ...; tn], constructs the application (t1 ... tn) *) let mkAppL a = DOPN (AppL, a) @@ -234,7 +518,7 @@ let mkMutInd (ind_sp,l) = DOPN (MutInd ind_sp, l) let mkMutConstruct (cstr_sp,l) = DOPN (MutConstruct cstr_sp,l) (* Constructs the term <p>Case c of c1 | c2 .. | cn end *) -let mkMutCase ci p c ac = +let mkMutCase (ci, p, c, ac) = DOPN (MutCase ci, Array.append [|p;c|] (Array.of_list ac)) let mkMutCaseA ci p c ac = DOPN (MutCase ci, Array.append [|p;c|] ac) @@ -316,7 +600,6 @@ let destMeta = function | (DOP0 (Meta n)) -> n | _ -> invalid_arg "destMeta" -let isMETA = function DOP0(Meta _) -> true | _ -> false (* Destructs a variable *) let destVar = function @@ -416,9 +699,12 @@ let rec strip_all_casts t = | DOP1(oper,c) -> DOP1(oper,strip_all_casts c) | DOP2(oper,c1,c2) -> DOP2(oper,strip_all_casts c1,strip_all_casts c2) | DOPN(oper,cl) -> DOPN(oper,Array.map strip_all_casts cl) - | DOPL(oper,cl) -> DOPL(oper,List.map strip_all_casts cl) | DLAM(na,c) -> DLAM(na,strip_all_casts c) | DLAMV(na,c) -> DLAMV(na,Array.map (under_outer_cast strip_all_casts) c) + | CLam (n,t,c) -> CLam (n, strip_all_casts t, strip_all_casts c) + | CPrd (n,t,c) -> CPrd (n, strip_all_casts t, strip_all_casts c) + | CLet (n,b,t,c) -> CLet (n, strip_all_casts b, strip_all_casts t, + strip_all_casts c) | VAR _ as t -> t | Rel _ as t -> t @@ -430,13 +716,13 @@ let isVar = function VAR _ -> true | _ -> false (* Destructs the product (x:t1)t2 *) let destProd = function - | DOP2 (Prod, t1, (DLAM (x,t2))) -> (x,t1,t2) + | CPrd (x,t1,t2) -> (x,t1,t2) | _ -> invalid_arg "destProd" let rec hd_of_prod prod = match strip_outer_cast prod with - | DOP2(Prod,c,DLAM(n,t')) -> hd_of_prod t' - | t -> t + | CPrd (n,c,t') -> hd_of_prod t' + | t -> t let hd_is_constructor t = let is_constructor = function @@ -449,9 +735,14 @@ let hd_is_constructor t = (* Destructs the abstraction [x:t1]t2 *) let destLambda = function - | DOP2 (Lambda, t1, (DLAM (x,t2))) -> (x,t1,t2) + | CLam (x,t1,t2) -> (x,t1,t2) | _ -> invalid_arg "destLambda" +(* Destructs the let [x:=b:t1]t2 *) +let destLetIn = function + | CLet (x,b,t1,t2) -> (x,b,t1,t2) + | _ -> invalid_arg "destProd" + (* Destructs an application *) let destAppL = function | (DOPN (AppL,a)) -> a @@ -461,8 +752,6 @@ let destApplication = function | (DOPN (AppL,a)) when Array.length a <> 0 -> (a.(0), array_tl a) | _ -> invalid_arg "destApplication" -let isAppL = function DOPN(AppL,_) -> true | _ -> false - let args_app = function | DOPN(AppL,cl) -> if Array.length cl >1 then array_tl cl else [||] | c -> [||] @@ -573,9 +862,9 @@ let destCoFix = function (**********************************************************************) -type binder_kind = BProd | BLambda +type binder_kind = BProd | BLambda | BLetIn -type fix_kind = RFix of (int array * int) | RCofix of int +type fix_kind = RFix of (int array * int) | RCoFix of int type 'ctxt reference = | RConst of section_path * 'ctxt @@ -596,6 +885,12 @@ type cofixpoint = int * (constr array * name list * constr array) (* Term analysis *) (******************) +type hnftype = + | HnfSort of sorts + | HnfProd of name * constr * constr + | HnfAtom of constr + | HnfMutInd of inductive * constr array + type kindOfTerm = | IsRel of int | IsMeta of int @@ -605,6 +900,7 @@ type kindOfTerm = | IsCast of constr * constr | IsProd of name * constr * constr | IsLambda of name * constr * constr + | IsLetIn of name * constr * constr * constr | IsAppL of constr * constr list | IsAbst of section_path * constr array | IsEvar of existential @@ -629,8 +925,9 @@ let kind_of_term c = | DOP0 (Sort s) -> IsSort s | DOP0 (XTRA s) -> IsXtra s | DOP2 (Cast, t1, t2) -> IsCast (t1,t2) - | DOP2 (Prod, t1, (DLAM (x,t2))) -> IsProd (x,t1,t2) - | DOP2 (Lambda, t1, (DLAM (x,t2))) -> IsLambda (x,t1,t2) + | CPrd (x,t1,t2) -> IsProd (x,t1,t2) + | CLam (x,t1,t2) -> IsLambda (x,t1,t2) + | CLet (x,b,t1,t2) -> IsLetIn (x,b,t1,t2) | DOPN (AppL,a) when Array.length a <> 0 -> IsAppL (a.(0), List.tl (Array.to_list a)) | DOPN (Const sp, a) -> IsConst (sp,a) @@ -648,26 +945,31 @@ let kind_of_term c = IsCoFix (i,typedbodies) | _ -> errorlabstrm "Term.kind_of_term" [< 'sTR "ill-formed constr" >] +let isMeta = function DOP0(Meta _) -> true | _ -> false +let isConst = function DOPN(Const _,_) -> true | _ -> false +let isMutConstruct = function DOPN(MutCase _,_) -> true | _ -> false +let isAppL = function DOPN(AppL,_) -> true | _ -> false + (***************************) (* Other term constructors *) (***************************) -let abs_implicit c = mkLambda Anonymous mkImplicit c -let lambda_implicit a = mkLambda (Name(id_of_string"y")) mkImplicit a +let abs_implicit c = mkLambda (Anonymous, mkImplicit, c) +let lambda_implicit a = mkLambda (Name(id_of_string"y"), mkImplicit, a) let lambda_implicit_lift n a = iterate lambda_implicit n (lift n a) (* prod_it b [xn:Tn;..;x1:T1] = (x1:T1)..(xn:Tn)b *) -let prod_it = List.fold_left (fun c (n,t) -> mkProd n t c) +let prod_it = List.fold_left (fun c (n,t) -> mkProd (n, t, c)) (* lam_it b [xn:Tn;..;x1:T1] = [x1:T1]..[xn:Tn]b *) -let lam_it = List.fold_left (fun c (n,t) -> mkLambda n t c) +let lam_it = List.fold_left (fun c (n,t) -> mkLambda (n, t, c)) (* prodn n [xn:Tn;..;x1:T1;Gamma] b = (x1:T1)..(xn:Tn)b *) let prodn n env b = let rec prodrec = function | (0, env, b) -> b - | (n, ((v,t)::l), b) -> prodrec (n-1, l, DOP2(Prod,t,DLAM(v,b))) + | (n, ((v,t)::l), b) -> prodrec (n-1, l, CPrd (v,t,b)) | _ -> assert false in prodrec (n,env,b) @@ -676,7 +978,7 @@ let prodn n env b = let lamn n env b = let rec lamrec = function | (0, env, b) -> b - | (n, ((v,t)::l), b) -> lamrec (n-1, l, DOP2(Lambda,t,DLAM(v,b))) + | (n, ((v,t)::l), b) -> lamrec (n-1, l, CLam (v,t,b)) | _ -> assert false in lamrec (n,env,b) @@ -712,8 +1014,7 @@ let rec to_lambda n prod = prod else match prod with - | DOP2(Prod,ty,DLAM(na,bd)) -> - DOP2(Lambda,ty,DLAM(na, to_lambda (n-1) bd)) + | CPrd(na,ty,bd) -> CLam(na,ty,to_lambda (n-1) bd) | DOP2(Cast,c,_) -> to_lambda n c | _ -> errorlabstrm "to_lambda" [<>] @@ -722,8 +1023,7 @@ let rec to_prod n lam = lam else match lam with - | DOP2(Lambda,ty,DLAM(na,bd)) -> - DOP2(Prod,ty,DLAM(na, to_prod (n-1) bd)) + | CLam(na,ty,bd) -> CPrd(na,ty,to_prod (n-1) bd) | DOP2(Cast,c,_) -> to_prod n c | _ -> errorlabstrm "to_prod" [<>] @@ -733,7 +1033,7 @@ let rec to_prod n lam = let prod_app t n = match strip_outer_cast t with - | DOP2(Prod,_,DLAM(na,b)) -> subst1 n b + | CPrd (_,_,b) -> subst1 n b | _ -> errorlabstrm "prod_app" [< 'sTR"Needed a product, but didn't find one" ; 'fNL >] @@ -753,27 +1053,29 @@ let prod_applist t nL = List.fold_left prod_app t nL (* Transforms a product term (x1:T1)..(xn:Tn)T into the pair ([(xn,Tn);...;(x1,T1)],T), where T is not a product *) let destArity = - let rec prodec_rec l = function - | DOP2(Prod,t,DLAM(x,c)) -> prodec_rec ((x,t)::l) c - | DOP2(Cast,c,_) -> prodec_rec l c - | DOP0(Sort s) -> l,s - | _ -> anomaly "decompose_arity: not an arity" + let rec prodec_rec l c = + match kind_of_term c with + | IsProd (x,t,c) -> prodec_rec ((x,t)::l) c + | IsCast (c,_) -> prodec_rec l c + | IsSort s -> l,s + | _ -> anomaly "decompose_arity: not an arity" in prodec_rec [] -let rec isArity = function - | DOP2(Prod,_,DLAM(_,c)) -> isArity c - | DOP2(Cast,c,_) -> isArity c - | DOP0(Sort _) -> true +let rec isArity c = + match kind_of_term c with + | IsProd (_,_,c) -> isArity c + | IsCast (c,_) -> isArity c + | IsSort _ -> true | _ -> false (* Transforms a product term (x1:T1)..(xn:Tn)T into the pair ([(xn,Tn);...;(x1,T1)],T), where T is not a product *) let decompose_prod = let rec prodec_rec l = function - | DOP2(Prod,t,DLAM(x,c)) -> prodec_rec ((x,t)::l) c - | DOP2(Cast,c,_) -> prodec_rec l c - | c -> l,c + | CPrd(x,t,c) -> prodec_rec ((x,t)::l) c + | DOP2(Cast,c,_) -> prodec_rec l c + | c -> l,c in prodec_rec [] @@ -781,9 +1083,9 @@ let decompose_prod = ([(xn,Tn);...;(x1,T1)],T), where T is not a lambda *) let decompose_lam = let rec lamdec_rec l = function - | DOP2(Lambda,t,DLAM(x,c)) -> lamdec_rec ((x,t)::l) c - | DOP2(Cast,c,_) -> lamdec_rec l c - | c -> l,c + | CLam (x,t,c) -> lamdec_rec ((x,t)::l) c + | DOP2 (Cast,c,_) -> lamdec_rec l c + | c -> l,c in lamdec_rec [] @@ -794,8 +1096,8 @@ let decompose_prod_n n = let rec prodec_rec l n c = if n=0 then l,c else match c with - | DOP2(Prod,t,DLAM(x,c)) -> prodec_rec ((x,t)::l) (n-1) c - | DOP2(Cast,c,_) -> prodec_rec l n c + | CPrd (x,t,c) -> prodec_rec ((x,t)::l) (n-1) c + | DOP2 (Cast,c,_) -> prodec_rec l n c | c -> error "decompose_prod_n: not enough products" in prodec_rec [] n @@ -807,8 +1109,8 @@ let decompose_lam_n n = let rec lamdec_rec l n c = if n=0 then l,c else match c with - | DOP2(Lambda,t,DLAM(x,c)) -> lamdec_rec ((x,t)::l) (n-1) c - | DOP2(Cast,c,_) -> lamdec_rec l n c + | CLam (x,t,c) -> lamdec_rec ((x,t)::l) (n-1) c + | DOP2 (Cast,c,_) -> lamdec_rec l n c | c -> error "decompose_lam_n: not enough abstractions" in lamdec_rec [] n @@ -817,7 +1119,7 @@ let decompose_lam_n n = * gives n (casts are ignored) *) let nb_lam = let rec nbrec n = function - | DOP2(Lambda,_,DLAM(_,c)) -> nbrec (n+1) c + | CLam (_,_,c) -> nbrec (n+1) c | DOP2(Cast,c,_) -> nbrec n c | _ -> n in @@ -826,145 +1128,13 @@ let nb_lam = (* similar to nb_lam, but gives the number of products instead *) let nb_prod = let rec nbrec n = function - | DOP2(Prod,_,DLAM(_,c)) -> nbrec (n+1) c + | CPrd (_,_,c) -> nbrec (n+1) c | DOP2(Cast,c,_) -> nbrec n c | _ -> n in nbrec 0 -(* Trop compliqué... -(********************************************************************) -(* various utility functions for implementing terms with bindings *) -(********************************************************************) - -let extract_lifted (n,x) = lift n x -let insert_lifted x = (0,x) - -(* l is a list of pairs (n:nat,x:constr), env is a stack of (na:name,T:constr) - push_and_lift adds a component to env and lifts l one step *) -let push_and_lift (na,t) env l = - ((na,t)::env, List.map (fun (n,x) -> (n+1,x)) l) - - -(* if T is not (x1:A1)(x2:A2)....(xn:An)T' then (push_and_liftl n env T l) - raises an error else it gives ([x1,A1 ; x2,A2 ; ... ; xn,An]@env,T',l') - where l' is l lifted n steps *) -let push_and_liftl n env t l = - let rec pushrec n t (env,l) = - match (n,t) with - | (0, _) -> (env,t,l) - | (_, DOP2(Prod,t,DLAM(na,b))) -> - pushrec (n-1) b (push_and_lift (na,t) env l) - | (_, DOP2(Cast,t,_)) -> pushrec n t (env,l) - | _ -> error "push_and_liftl" - in - pushrec n t (env,l) - -(* if T is not (x1:A1)(x2:A2)....(xn:An)T' then (push_and_liftl n env T l) - raises an error else it gives ([x1,A1 ; x2,A2 ; ... ; xn,An]@env,T',l') - where l' is l lifted n steps *) -let push_lam_and_liftl n env t l = - let rec pushrec n t (env,l) = - match (n,t) with - | (0, _) -> (env,t,l) - | (_, DOP2(Lambda,t,DLAM(na,b))) -> - pushrec (n-1) b (push_and_lift (na,t) env l) - | (_, DOP2(Cast,t,_)) -> pushrec n t (env,l) - | _ -> error "push_lam_and_liftl" - in - pushrec n t (env,l) - -(* l is a list of pairs (n:nat,x:constr), tlenv is a stack of -(na:name,T:constr), B : constr, na : name -(prod_and_pop ((na,T)::tlenv) B l) gives (tlenv, (na:T)B, l') -where l' is l lifted down one step *) -let prod_and_pop env b l = - match env with - | [] -> error "prod_and_pop" - | (na,t)::tlenv -> - (tlenv,DOP2(Prod,t,DLAM(na,b)), - List.map (function - (0,x) -> (0,lift (-1) x) - | (n,x) -> (n-1,x)) l) - -(* recusively applies prod_and_pop : -if env = [na1:T1 ; na2:T2 ; ... ; nan:Tn]@tlenv -then -(prod_and_popl n env T l) gives (tlenv,(nan:Tn)...(na1:Ta1)T,l') where -l' is l lifted down n steps *) -let prod_and_popl n env t l = - let rec poprec = function - | (0, (env,b,l)) -> (env,b,l) - | (n, ([],_,_)) -> error "prod_and_popl" - | (n, (env,b,l)) -> poprec (n-1, prod_and_pop env b l) - in - poprec (n,(env,t,l)) - -(* similar to prod_and_pop, but gives [na:T]B intead of (na:T)B *) -let lam_and_pop env b l = - match env with - | [] -> error "lam_and_pop" - | (na,t)::tlenv -> - (tlenv,DOP2(Lambda,t,DLAM(na,b)), - List.map (function - (0,x) -> (0,lift (-1) x) - | (n,x) -> (n-1,x)) l) - -(* similar to lamn_and_pop but generates new names whenever the name is - * Anonymous *) -let lam_and_pop_named env body l acc_ids = - match env with - | [] -> error "lam_and_pop" - | (na,t)::tlenv -> - let id = match na with - | Anonymous -> next_ident_away (id_of_string "a") acc_ids - | Name id -> id - in - (tlenv,DOP2(Lambda,t,DLAM((Name id),body)), - List.map (function - | (0,x) -> (0,lift (-1) x) - | (n,x) -> (n-1,x)) l, - (id::acc_ids)) - -(* similar to prod_and_popl but gives [nan:Tan]...[na1:Ta1]B instead of - * (nan:Tan)...(na1:Ta1)B *) -let lam_and_popl n env t l = - let rec poprec = function - | (0, (env,b,l)) -> (env,b,l) - | (n, ([],_,_)) -> error "lam_and_popl" - | (n, (env,b,l)) -> poprec (n-1, lam_and_pop env b l) - in - poprec (n,(env,t,l)) - -(* similar to prod_and_popl but gives [nan:Tan]...[na1:Ta1]B instead of - * but it generates names whenever nai=Anonymous *) - -let lam_and_popl_named n env t l = - let rec poprec = function - | (0, (env,b,l,_)) -> (env,b,l) - | (n, ([],_,_,_)) -> error "lam_and_popl" - | (n, (env,b,l,acc_ids)) -> poprec (n-1, lam_and_pop_named env b l acc_ids) - in - poprec (n,(env,t,l,[])) - -(* [lambda_ize n T endpt] - * will pop off the first [n] products in [T], then stick in [endpt], - * properly lifted, and then push back the products, but as lambda- - * abstractions *) -let lambda_ize n t endpt = - let env = [] - and carry = [insert_lifted endpt] in - let env, endpt = - match push_and_liftl n env t carry with - | (env,_,[endpt]) -> env, endpt - | _ -> anomaly "bud in Term.lamda_ize" - in - let t = extract_lifted endpt in - match lam_and_popl n env t [] with - | (_,t,[]) -> t - | _ -> anomaly "bud in Term.lamda_ize" -*) - +(* Misc *) let sort_hdchar = function | Prop(_) -> "P" | Type(_) -> "T" @@ -1021,17 +1191,65 @@ let rec strip_head_cast = function | DOP2(Cast,c,t) -> strip_head_cast c | c -> c +(* Returns the list of global variables in a term *) + +let global_varsl l constr = + let rec filtrec acc = function + | VAR id -> id::acc + | DOP1(oper,c) -> filtrec acc c + | DOP2(oper,c1,c2) -> filtrec (filtrec acc c1) c2 + | DOPN(oper,cl) -> Array.fold_left filtrec acc cl + | DLAM(_,c) -> filtrec acc c + | DLAMV(_,v) -> Array.fold_left filtrec acc v + | CLam (_,t,c) -> filtrec (filtrec acc t) c + | CPrd (_,t,c) -> filtrec (filtrec acc t) c + | CLet (_,b,t,c) -> filtrec (filtrec (filtrec acc b) t) c + | _ -> acc + in + filtrec l constr + +let global_vars constr = global_varsl [] constr + +let global_vars_set constr = + let rec filtrec acc = function + | VAR id -> Idset.add id acc + | DOP1(oper,c) -> filtrec acc c + | DOP2(oper,c1,c2) -> filtrec (filtrec acc c1) c2 + | DOPN(oper,cl) -> Array.fold_left filtrec acc cl + | DLAM(_,c) -> filtrec acc c + | DLAMV(_,v) -> Array.fold_left filtrec acc v + | CLam (_,t,c) -> filtrec (filtrec acc t) c + | CPrd (_,t,c) -> filtrec (filtrec acc t) c + | CLet (_,b,t,c) -> filtrec (filtrec (filtrec acc b) t) c + | _ -> acc + in + filtrec Idset.empty constr + +(* [Rel (n+m);...;Rel(n+1)] *) + +let rel_vect n m = Array.init m (fun i -> Rel(n+m-i)) + +let rel_list n m = + let rec reln l p = + if p>m then l else reln (Rel(n+p)::l) (p+1) + in + reln [] 1 + +(* Rem: end of import from old module Generic *) + (* Various occurs checks *) let occur_opern s = let rec occur_rec = function | DOPN(oper,cl) -> s=oper or (array_exists occur_rec cl) - | DOPL(oper,cl) -> s=oper or (List.exists occur_rec cl) | VAR _ -> false | DOP1(_,c) -> occur_rec c | DOP2(_,c1,c2) -> (occur_rec c1) or (occur_rec c2) | DLAM(_,c) -> occur_rec c | DLAMV(_,v) -> array_exists occur_rec v + | CLam (_,t,c) -> occur_rec t or occur_rec c + | CPrd (_,t,c) -> occur_rec t or occur_rec c + | CLet (_,b,t,c) -> occur_rec b or occur_rec t or occur_rec c | _ -> false in occur_rec @@ -1044,12 +1262,14 @@ let occur_evar ev = occur_opern (Evar ev) let occur_var s = let rec occur_rec = function | DOPN(_,cl) -> array_exists occur_rec cl - | DOPL(_,cl) -> List.exists occur_rec cl | VAR id -> s=id | DOP1(_,c) -> occur_rec c | DOP2(_,c1,c2) -> (occur_rec c1) or (occur_rec c2) | DLAM(_,c) -> occur_rec c | DLAMV(_,v) -> array_exists occur_rec v + | CLam (_,t,c) -> occur_rec t or occur_rec c + | CPrd (_,t,c) -> occur_rec t or occur_rec c + | CLet (_,b,t,c) -> occur_rec b or occur_rec t or occur_rec c | _ -> false in occur_rec @@ -1068,7 +1288,6 @@ let occur_var s = - if no (sp,_) appears in sigma, then sp is not unfolded. - NOTE : the case of DOPL is not handled... *) let replace_consts const_alist = let rec substrec = function @@ -1090,11 +1309,13 @@ let replace_consts const_alist = | DOP2(oper,c1,c2) -> DOP2(oper,substrec c1,substrec c2) | DLAM(na,c) -> DLAM(na,substrec c) | DLAMV(na,v) -> DLAMV(na,Array.map substrec v) + | CLam (na,t,c) -> CLam (na, substrec t, substrec c) + | CPrd (na,t,c) -> CPrd (na, substrec t, substrec c) + | CLet (na,b,t,c) -> CLet (na, substrec b, substrec t, substrec c) | x -> x in if const_alist = [] then function x -> x else substrec -(* NOTE : the case of DOPL is not handled by whd_castapp_stack *) let whd_castapp_stack = let rec whrec x stack = match x with | DOPN(AppL,cl) -> whrec (array_hd cl) (array_app_tl cl stack) @@ -1129,41 +1350,31 @@ let rec eq_constr_rec m n = | (DLAM(_,c1),DLAM(_,c2)) -> eq_constr_rec c1 c2 | (DLAMV(_,cl1),DLAMV(_,cl2)) -> array_for_all2 eq_constr_rec cl1 cl2 + | CLam(_,t1,c1), CLam(_,t2,c2) -> eq_constr_rec t1 t2 & eq_constr_rec c1 c2 + | CPrd(_,t1,c1), CPrd(_,t2,c2) -> eq_constr_rec t1 t2 & eq_constr_rec c1 c2 + | CLet(_,b1,t1,c1), CLet (_,b2,t2,c2) -> + eq_constr_rec b1 b2 & eq_constr_rec t1 t2 & eq_constr_rec c1 c2 | _ -> false let eq_constr = eq_constr_rec -let rec eq_constr_with_meta_rec m n= - (m == n) or - (m=n) or - (match (strip_head_cast m,strip_head_cast n) with - | (Rel p1,Rel p2) -> p1=p2 - | (DOPN(oper1,cl1),DOPN(oper2,cl2)) -> - oper1=oper2 & array_for_all2 eq_constr_rec cl1 cl2 - | (DOP0 oper1,DOP0 oper2) -> oper1=oper2 - | (DOP1(i,c1),DOP1(j,c2)) -> (i=j) & eq_constr_rec c1 c2 - | (DOP2(i,c1,c1'),DOP2(j,c2,c2')) -> - (i=j) & eq_constr_rec c1 c2 & eq_constr_rec c1' c2' - | (DLAM(_,c1),DLAM(_,c2)) -> eq_constr_rec c1 c2 - | (DLAMV(_,cl1),DLAMV(_,cl2)) -> - array_for_all2 eq_constr_rec cl1 cl2 - | _ -> false) - (* (dependent M N) is true iff M is eq_term with a subterm of N M is appropriately lifted through abstractions of N *) let dependent = let rec deprec m t = - (eq_constr m t) - or (match t with - | VAR _ -> false - | DOP1(_,c) -> deprec m c - | DOP2(_,c,t) -> deprec m c or deprec m t - | DOPN(_,cl) -> array_exists (deprec m) cl - | DOPL(_,cl) -> List.exists (deprec m) cl - | DLAM(_,c) -> deprec (lift 1 m) c - | DLAMV(_,v) -> array_exists (deprec (lift 1 m)) v - | _ -> false) + (eq_constr m t) or + (match t with + | VAR _ -> false + | DOP1(_,c) -> deprec m c + | DOP2(_,c,t) -> deprec m c or deprec m t + | DOPN(_,cl) -> array_exists (deprec m) cl + | DLAM(_,c) -> deprec (lift 1 m) c + | DLAMV(_,v) -> array_exists (deprec (lift 1 m)) v + | CLam (_,t,c) -> deprec m t or deprec (lift 1 m) c + | CPrd (_,t,c) -> deprec m t or deprec (lift 1 m) c + | CLet (_,b,t,c) -> deprec m b or deprec m t or deprec (lift 1 m) c + | _ -> false) in deprec @@ -1173,7 +1384,7 @@ let dependent = let rec eta_reduce_head c = match c with - | DOP2(Lambda,c1,DLAM(_,c')) -> + | CLam (_,c1,c') -> (match eta_reduce_head c' with | DOPN(AppL,cl) -> let lastn = (Array.length cl) - 1 in @@ -1185,7 +1396,7 @@ let rec eta_reduce_head c = if lastn = 1 then cl.(0) else DOPN(AppL,Array.sub cl 0 lastn) in - if (not ((dependent (Rel 1) c'))) + if (not ((dependent (mkRel 1) c'))) then lift (-1) c' else c | _ -> c) @@ -1194,40 +1405,43 @@ let rec eta_reduce_head c = (* alpha-eta conversion : ignore print names and casts *) -let rec eta_eq_constr t1 t2 = - let t1 = eta_reduce_head (strip_head_cast t1) - and t2 = eta_reduce_head (strip_head_cast t2) in - t1=t2 or match (t1,t2) with - | (DOP2(Cast,c1,_),c2) -> eta_eq_constr c1 c2 - | (c1,DOP2(Cast,c2,_)) -> eta_eq_constr c1 c2 +let eta_eq_constr = + let rec aux t1 t2 = + let t1 = eta_reduce_head (strip_head_cast t1) + and t2 = eta_reduce_head (strip_head_cast t2) in + t1=t2 or match (t1,t2) with + | (DOP2(Cast,c1,_),c2) -> aux c1 c2 + | (c1,DOP2(Cast,c2,_)) -> aux c1 c2 | (Rel p1,Rel p2) -> p1=p2 - | (DOPN(oper1,cl1),DOPN(oper2,cl2)) -> - oper1=oper2 & array_for_all2 eta_eq_constr cl1 cl2 - | (DOP0 oper1,DOP0 oper2) -> oper1=oper2 - | (DOP1(i,c1),DOP1(j,c2)) -> (i=j) & eta_eq_constr c1 c2 - | (DOP2(i,c1,c1'),DOP2(j,c2,c2')) -> - (i=j) & eta_eq_constr c1 c2 & eta_eq_constr c1' c2' - | (DLAM(_,c1),DLAM(_,c2)) -> eta_eq_constr c1 c2 - | (DLAMV(_,cl1),DLAMV(_,cl2)) -> array_for_all2 eta_eq_constr cl1 cl2 + | (DOPN(op1,cl1),DOPN(op2,cl2)) -> op1=op2 & array_for_all2 aux cl1 cl2 + | (DOP0 oper1,DOP0 oper2) -> oper1=oper2 + | (DOP1(i,c1),DOP1(j,c2)) -> (i=j) & aux c1 c2 + | (DOP2(i,c1,c1'),DOP2(j,c2,c2')) -> (i=j) & aux c1 c2 & aux c1' c2' + | (DLAM(_,c1),DLAM(_,c2)) -> aux c1 c2 + | (DLAMV(_,cl1),DLAMV(_,cl2)) -> array_for_all2 aux cl1 cl2 + | CLam(_,t1,c1), CLam(_,t2,c2) -> aux t1 t2 & aux c1 c2 + | CPrd(_,t1,c1), CPrd(_,t2,c2) -> aux t1 t2 & aux c1 c2 + | CLet(_,b1,t1,c1), CLet (_,b2,t2,c2) -> aux b1 b2 & aux t1 t2 & aux c1 c2 | _ -> false + in aux -(* This renames bound variablew with fresh and distinct names *) +(* This renames bound variables with fresh and distinct names *) (* in such a way that the printer doe not generate new names *) (* and therefore that printed names are the intern names *) (* In this way, tactics such as Induction works well *) -let rec rename_bound_var l = function - | DOP2(Prod,c1,DLAM(Name(s),c2)) -> - if dependent (Rel 1) c2 then +let rec rename_bound_var l c = + match kind_of_term c with + | IsProd (Name s,c1,c2) -> + if dependent (mkRel 1) c2 then let s' = next_ident_away s (global_vars c2@l) in - DOP2(Prod,c1,DLAM(Name(s'),rename_bound_var (s'::l) c2)) + mkProd (Name s', c1, rename_bound_var (s'::l) c2) else - DOP2(Prod,c1,DLAM(Name(s),rename_bound_var l c2)) - | DOP2(Prod,c1,DLAM(Anonymous,c2)) -> - DOP2(Prod,c1,DLAM(Anonymous,rename_bound_var l c2)) - | DOP2(Cast,c,t) -> DOP2(Cast,rename_bound_var l c,t) - | x -> x + mkProd (Name s, c1, rename_bound_var l c2) + | IsProd (Anonymous,c1,c2) -> mkProd (Anonymous, c1, rename_bound_var l c2) + | IsCast (c,t) -> mkCast (rename_bound_var l c, t) + | x -> c (***************************) (* substitution functions *) @@ -1269,47 +1483,38 @@ let sort_increasing_snd = [subst_term c t] substitutes [(Rel 1)] for all occurrences of (closed) term [c] in a term [t] *) -let subst_term c t = +let subst_term_gen eq_fun c t = let rec substrec k c t = match prefix_application k c t with | Some x -> x | None -> - (if eq_constr t c then Rel(k) else match t with - | DOPN(Const sp,cl) -> t - | DOPN(MutInd (x_0,x_1),cl) -> t - | DOPN(MutConstruct (x_0,x_1),cl) -> t - | DOPN(oper,tl) -> DOPN(oper,Array.map (substrec k c) tl) - | DOP1(i,t) -> DOP1(i,substrec k c t) - | DOP2(oper,c1,c2) -> DOP2(oper,substrec k c c1,substrec k c c2) - | DLAM(na,t) -> DLAM(na,substrec (k+1) (lift 1 c) t) - | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (k+1) (lift 1 c)) v) - | _ -> t) + (if eq_fun t c then Rel(k) else match t with + | DOPN(Const sp,cl) -> t + | DOPN(MutInd (x_0,x_1),cl) -> t + | DOPN(MutConstruct (x_0,x_1),cl) -> t + | DOPN(oper,tl) -> DOPN(oper,Array.map (substrec k c) tl) + | DOP1(i,t) -> DOP1(i,substrec k c t) + | DOP2(oper,c1,c2) -> DOP2(oper,substrec k c c1,substrec k c c2) + | DLAM(na,t) -> DLAM(na,substrec (k+1) (lift 1 c) t) + | DLAMV(na,v) -> DLAMV(na,Array.map (substrec (k+1) (lift 1 c)) v) + | CLam(na,t,c2) -> CLam(na,substrec k c t,substrec (k+1) (lift 1 c) c2) + | CPrd(na,t,c2) -> CPrd(na,substrec k c t,substrec (k+1) (lift 1 c) c2) + | CLet(na,b,t,c2) -> CLet(na,substrec k c b,substrec k c t, + substrec (k+1) (lift 1 c) c2) + | _ -> t) in substrec 1 c t -(* same as subst_term, but modulo eta *) - -let subst_term_eta_eq c t = - let rec substrec k c t = - match prefix_application_eta k c t with - | Some x -> x - | None -> - (if eta_eq_constr t c then Rel(k) else match t with - | DOPN(Const sp,cl) -> t - | DOPN(oper,tl) -> DOPN(oper,Array.map (substrec k c) tl) - | DOP1(i,t) -> DOP1(i,substrec k c t) - | DOP2(oper,c1,c2) -> DOP2(oper,substrec k c c1,substrec k c c2) - | DLAM(na,t) -> DLAM(na,substrec (k+1) (lift 1 c) t) - | DLAMV(na,v)-> DLAMV(na,Array.map (substrec (k+1) (lift 1 c)) v) - | _ -> t) - in - substrec 1 c t +let subst_term = subst_term_gen eq_constr +let subst_term_eta = subst_term_gen eta_eq_constr (* bl : (int,constr) Listmap.t = (int * constr) list *) (* c : constr *) (* for each binding (i,c_i) in bl, substitutes the metavar i by c_i in c *) (* Raises Not_found if c contains a meta that is not in the association list *) +(* Bogué ? Pourquoi pas de lift en passant sous un lieur ?? *) +(* Et puis meta doit fusionner avec Evar *) let rec subst_meta bl c = match c with | DOP0(Meta(i)) -> List.assoc i bl @@ -1317,6 +1522,10 @@ let rec subst_meta bl c = | DOP2(op,c'1, c'2) -> DOP2(op, subst_meta bl c'1, subst_meta bl c'2) | DOPN(op, c') -> DOPN(op, Array.map (subst_meta bl) c') | DLAM(x,c') -> DLAM(x, subst_meta bl c') + | CLam(na,t,c) -> CLam(na,subst_meta bl t,subst_meta bl c) + | CPrd(na,t,c) -> CPrd(na,subst_meta bl t,subst_meta bl c) + | CLet(na,b,t,c) -> CLet(na,subst_meta bl b,subst_meta bl t, + subst_meta bl c) | _ -> c (* Substitute only a list of locations locs, the empty list is @@ -1325,55 +1534,61 @@ let rec subst_meta bl c = that will not be substituted. *) let subst_term_occ_gen locs occ c t = + let pos = ref occ in let except = List.for_all (fun n -> n<0) locs in - let rec substcheck k occ c t = - if except or List.exists (function u -> u>=occ) locs then - substrec k occ c t + let rec substcheck k c t = + if except or List.exists (function u -> u >= !pos) locs then + substrec k c t else - (occ,t) - and substrec k occ c t = + t + and substrec k c t = if eq_constr t c then - if except then - if List.mem (-occ) locs then (occ+1,t) else (occ+1,Rel(k)) - else - if List.mem occ locs then (occ+1,Rel(k)) else (occ+1,t) - else + let r = + if except then + if List.mem (- !pos) locs then t else (Rel k) + else + if List.mem !pos locs then (Rel k) else t + in incr pos; r + else match t with - | DOPN(Const sp,tl) -> occ,t - | DOPN(MutConstruct _,tl) -> occ,t - | DOPN(MutInd _,tl) -> occ,t - | DOPN(i,cl) -> - let (occ',cl') = - Array.fold_left - (fun (nocc',lfd) f -> - let (nocc'',f') = substcheck k nocc' c f in - (nocc'',f'::lfd)) - (occ,[]) cl - in - (occ',DOPN(i,Array.of_list (List.rev cl'))) - | DOP2(i,t1,t2) -> - let (nocc1,t1')=substrec k occ c t1 in - let (nocc2,t2')=substcheck k nocc1 c t2 in - nocc2,DOP2(i,t1',t2') - | DOP1(i,t) -> - let (nocc,t')= substrec k occ c t in - nocc,DOP1(i,t') - | DLAM(n,t) -> - let (occ',t') = substcheck (k+1) occ (lift 1 c) t in - (occ',DLAM(n,t')) - | DLAMV(n,cl) -> - let (occ',cl') = + | DOPN((Const _ | MutConstruct _ | MutInd _), _) -> t + | DOPN(i,cl) -> + let cl' = + Array.fold_left (fun lfd f -> substcheck k c f :: lfd) [] cl + in + DOPN(i,Array.of_list (List.rev cl')) + | DOP2(i,t1,t2) -> + let t1' = substrec k c t1 in + let t2' = substcheck k c t2 in + DOP2(i,t1',t2') + | DOP1(i,t) -> + DOP1(i,substrec k c t) + | DLAM(n,t) -> + DLAM(n,substcheck (k+1) (lift 1 c) t) + | DLAMV(n,cl) -> + let cl' = Array.fold_left - (fun (nocc',lfd) f -> - let (nocc'',f') = - substcheck (k+1) nocc' (lift 1 c) f - in (nocc'',f'::lfd)) - (occ,[]) cl + (fun lfd f -> substcheck (k+1) (lift 1 c) f ::lfd) + [] cl in - (occ',DLAMV(n,Array.of_list (List.rev cl') )) - | _ -> occ,t + DLAMV(n,Array.of_list (List.rev cl')) + | CLam(na,t,c2) -> + let t' = substrec k c t in + let c2' = substcheck (k+1) (lift 1 c) c2 in + CLam(na,t',c2') + | CPrd(na,t,c2) -> + let t' = substrec k c t in + let c2' = substcheck (k+1) (lift 1 c) c2 in + CPrd(na,t',c2') + | CLet(na,b,t,c2) -> + let b' = substrec k c b in + let t' = substrec k c t in + let c2' = substcheck (k+1) (lift 1 c) c2 in + CLet(na,b',t',c2') + | DOP0 _ | VAR _ | Rel _ -> t in - substcheck 1 occ c t + let t' = substcheck 1 c t in + (!pos, t') let subst_term_occ locs c t = if locs = [] then @@ -1406,24 +1621,25 @@ let subst_term_occ_decl locs c (id,bodyopt,typ as d) = (***************************) let rec occur_meta = function - | DOP2(Prod,t,DLAM(_,c)) -> (occur_meta t) or (occur_meta c) - | DOP2(Lambda,t,DLAM(_,c)) -> (occur_meta t) or (occur_meta c) + | CPrd(_,t,c) -> (occur_meta t) or (occur_meta c) + | CLam(_,t,c) -> (occur_meta t) or (occur_meta c) + | CLet(_,b,t,c) -> (occur_meta b) or (occur_meta t) or (occur_meta c) | DOPN(_,cl) -> (array_exists occur_meta cl) | DOP2(Cast,c,t) -> occur_meta c or occur_meta t | DOP0(Meta(_)) -> true | _ -> false -let rel_vect = (Generic.rel_vect : int -> int -> constr array) - let occur_existential = let rec occrec = function | DOPN(Evar _,_) -> true | DOPN(_,cl) -> array_exists occrec cl - | DOPL(_,cl) -> List.exists occrec cl | DOP2(_,c1,c2) -> occrec c1 or occrec c2 | DOP1(_,c) -> occrec c | DLAM(_,c) -> occrec c | DLAMV(_,cl) -> array_exists occrec cl + | CPrd(_,t,c) -> (occrec t) or (occrec c) + | CLam(_,t,c) -> (occrec t) or (occrec c) + | CLet(_,b,t,c) -> (occrec b) or (occrec t) or (occrec c) | _ -> false in occrec @@ -1440,13 +1656,14 @@ let comp_term t1 t2 = | (DOPN(o1,v1), DOPN(o2,v2)) -> (o1==o2) & (Array.length v1 = Array.length v2) & array_for_all2 (==) v1 v2 - | (DOPL(o1,l1), DOPL(o2,l2)) -> - (o1==o2) & (List.length l1 = List.length l2) - & List.for_all2 (==) l1 l2 | (DLAM(x1,t1), DLAM(x2,t2)) -> x1==x2 & t1==t2 | (DLAMV(x1,v1), DLAMV(x2,v2)) -> (x1==x2) & (Array.length v1 = Array.length v2) & array_for_all2 (==) v1 v2 + | CLam(x1,t1,c1), CLam(x2,t2,c2) -> (x1==x2) & (t1==t2) & (c1==c2) + | CPrd(x1,t1,c1), CPrd(x2,t2,c2) -> (x1==x2) & (t1==t2) & (c1==c2) + | CLet(x1,b1,t1,c1), CLet (x2,b2,t2,c2) -> + (x1==x2) & (b1==b2) & (t1==t2) & (c1==c2) | (Rel i, Rel j) -> i=j | (VAR x, VAR y) -> x==y | _ -> false @@ -1457,9 +1674,11 @@ let hash_term (sh_rec,(sh_op,sh_na,sh_id)) t = | DOP1(o,t) -> DOP1(sh_op o, sh_rec t) | DOP2(o,t1,t2) -> DOP2(sh_op o, sh_rec t1, sh_rec t2) | DOPN(o,v) -> DOPN(sh_op o, Array.map sh_rec v) - | DOPL(o,l) -> DOPL(sh_op o, List.map sh_rec l) | DLAM(n,t) -> DLAM(sh_na n, sh_rec t) | DLAMV(n,v) -> DLAMV(sh_na n, Array.map sh_rec v) + | CLam (n,t,c) -> CLam (sh_na n, sh_rec t, sh_rec c) + | CPrd (n,t,c) -> CPrd (sh_na n, sh_rec t, sh_rec c) + | CLet (n,b,t,c) -> CLet (sh_na n, sh_rec b, sh_rec t, sh_rec c) | Rel i -> t | VAR x -> VAR (sh_id x) @@ -1568,204 +1787,138 @@ let is_hd_const=function Some (Const c,Array.of_list (List.tl (Array.to_list t))) |_ -> None) |_ -> None - -(*Gives the occurences number of t in u*) -let rec nb_occ_term t u= - let one_step t=function - | DOP1(_,c) -> nb_occ_term t c - | DOP2(_,c0,c1) -> (nb_occ_term t c0)+(nb_occ_term t c1) - | DOPN(_,a) -> Array.fold_left (fun a x -> a+(nb_occ_term t x)) 0 a - | DOPL(_,l) -> List.fold_left (fun a x -> a+(nb_occ_term t x)) 0 l - | DLAM(_,c) -> nb_occ_term t c - | DLAMV(_,a) -> Array.fold_left (fun a x -> a+(nb_occ_term t x)) 0 a - | _ -> 0 - in - if t=u then - 1 - else - one_step t u - -(*Alpha-conversion*) -let bind_eq=function - | (Anonymous,Anonymous) -> true - | (Name _,Name _) -> true - | _ -> false - - (*Tells if two constrs are equal modulo unification*) -let rec eq_mod_rel l_meta=function - | (t,DOP0(Meta n)) -> - if not(List.mem n (fst (List.split l_meta))) then - Some ([(n,t)]@l_meta) - else if (List.assoc n l_meta)=t then - Some l_meta - else - None - | DOP1(op0,c0), DOP1(op1,c1) -> - if op0=op1 then - eq_mod_rel l_meta (c0,c1) - else - None - | DOP2(op0,t0,c0), DOP2(op1,t1,c1) -> - if op0=op1 then - match (eq_mod_rel l_meta (t0,t1)) with - | None -> None - | Some l -> eq_mod_rel l (c0,c1) - else - None - | DOPN(op0,t0), DOPN(op1,t1) -> - if (op0=op1) & ((Array.length t0)=(Array.length t1)) then - List.fold_left2 - (fun a c1 c2 -> - match a with - | None -> None - | Some l -> eq_mod_rel l (c1,c2)) (Some l_meta) - (Array.to_list t0) (Array.to_list t1) - else - None - | DLAM(n0,t0),DLAM(n1,t1) -> - if (bind_eq (n0,n1)) then - eq_mod_rel l_meta (t0,t1) - else - None - | (t,u) -> - if t=u then Some l_meta else None - -(*Substitutes a list of meta l in t*) -let rec subst_with_lmeta l=function - | DOP0(Meta n) -> List.assoc n l - | DOP1(op,t) -> DOP1(op,subst_with_lmeta l t) - | DOP2(op,t0,t1) -> DOP2(op,subst_with_lmeta l t0,subst_with_lmeta l t1) - | DOPN(op,t) -> DOPN(op,Array.map (subst_with_lmeta l) t) - | DOPL(op,ld) -> DOPL(op,List.map (subst_with_lmeta l) ld) - | DLAM(n,t) -> DLAM(n,subst_with_lmeta l t) - | DLAMV(n,t) -> DLAMV(n,Array.map (subst_with_lmeta l) t) - | t -> t - -(*Carries out the following translation: DOPN(AppL,[|t|]) -> t and - DOPN(AppL,[|DOPN(AppL,t);...;t'|]) -> DOPN(AppL;[|t;...;t'|])*) -let rec appl_elim=function - | DOPN(AppL,t) -> - if (Array.length t)=1 then - appl_elim t.(0) - else - (match t.(0) with - | DOPN(AppL,t') -> - appl_elim (DOPN(AppL,Array.append t' - (Array.of_list - (List.tl (Array.to_list t))))) - |_ -> DOPN(AppL,Array.map appl_elim t)) - | DOP1(op,t) -> DOP1(op,appl_elim t) - | DOP2(op,t0,t1) -> DOP2(op,appl_elim t0,appl_elim t1) - | DOPN(op,t) -> DOPN(op,Array.map appl_elim t) - | DOPL(op,ld) -> DOPL(op,List.map appl_elim ld) - | DLAM(n,t) -> DLAM(n,appl_elim t) - | DLAMV(n,t) -> DLAMV(n,Array.map appl_elim t) - | t -> t - -(*Gives Some(first instance of ceq in cref,occurence number for this - instance) or None if no instance of ceq can be found in cref*) -let sub_term_with_unif cref ceq= - let rec find_match l_meta nb_occ op_ceq t_eq=function - | DOPN(AppL,t) as u -> - (match (t.(0)) with - | DOPN(op,t_op) -> - let t_args=Array.of_list (List.tl (Array.to_list t)) in - if op=op_ceq then - match - (List.fold_left2 - (fun a c0 c1 -> - match a with - | None -> None - | Some l -> eq_mod_rel l (c0,c1)) (Some l_meta) - (Array.to_list t_args) (Array.to_list t_eq)) - with - | None -> - List.fold_left - (fun (l_meta,nb_occ) x -> find_match l_meta nb_occ - op_ceq t_eq x) (l_meta,nb_occ) (Array.to_list - t_args) - | Some l -> (l,nb_occ+1) - else - List.fold_left - (fun (l_meta,nb_occ) x -> find_match l_meta - nb_occ op_ceq t_eq x) - (l_meta,nb_occ) (Array.to_list t) - | VAR _ -> - List.fold_left - (fun (l_meta,nb_occ) x -> find_match l_meta - nb_occ op_ceq t_eq x) - (l_meta,nb_occ) (Array.to_list t) - |_ -> (l_meta,nb_occ)) - | DOP2(_,t,DLAM(_,c)) -> - let (lt,nbt)=find_match l_meta nb_occ op_ceq t_eq t in - find_match lt nbt op_ceq t_eq c - | DOPN(_,t) -> - List.fold_left - (fun (l_meta,nb_occ) x -> find_match l_meta nb_occ op_ceq t_eq x) - (l_meta,nb_occ) (Array.to_list t) - |_ -> (l_meta,nb_occ) - in - match (is_hd_const ceq) with - | None -> - if (occur_meta ceq) then - None - else - let nb_occ=nb_occ_term ceq cref in - if nb_occ=0 then - None - else - Some (ceq,nb_occ) - | Some (head,t_args) -> - let (l,nb)=find_match [] 0 head t_args cref in - if nb=0 then - None - else - Some ((subst_with_lmeta l ceq),nb) + +(* Abstract decomposition of constr to deal with generic functions *) type constr_operator = | OpMeta of int | OpSort of sorts | OpRel of int | OpVar of identifier - | OpCast | OpProd of name | OpLambda of name + | OpCast | OpProd of name | OpLambda of name | OpLetIn of name | OpAppL | OpConst of section_path | OpAbst of section_path | OpEvar of existential_key | OpMutInd of inductive_path | OpMutConstruct of constructor_path | OpMutCase of case_info - | OpRec of fix_kind + | OpRec of fix_kind * name list let splay_constr = function - | Rel n -> OpRel n, [] - | VAR id -> OpVar id, [] - | DOP0 (Meta n) -> OpMeta n, [] - | DOP0 (Sort s) -> OpSort s, [] - | DOP2 (Cast, t1, t2) -> OpCast, [t1;t2] - | DOP2 (Prod, t1, (DLAM (x,t2))) -> OpProd x, [t1;t2] - | DOP2 (Lambda, t1, (DLAM (x,t2))) -> OpLambda x, [t1;t2] - | DOPN (AppL,a) -> OpAppL, Array.to_list a - | DOPN (Const sp, a) -> OpConst sp, Array.to_list a - | DOPN (Evar sp, a) -> OpEvar sp, Array.to_list a - | DOPN (MutInd ind_sp, l) -> OpMutInd ind_sp, Array.to_list l - | DOPN (MutConstruct cstr_sp,l) -> OpMutConstruct cstr_sp, Array.to_list l - | DOPN (MutCase ci,v) -> OpMutCase ci, Array.to_list v - | DOPN ((Fix (f,i),a)) -> OpRec (RFix (f,i)), Array.to_list a - | DOPN ((CoFix i),a) -> OpRec (RCofix i), Array.to_list a + | Rel n -> OpRel n, [||] + | VAR id -> OpVar id, [||] + | DOP0 (Meta n) -> OpMeta n, [||] + | DOP0 (Sort s) -> OpSort s, [||] + | DOP2 (Cast, t1, t2) -> OpCast, [|t1;t2|] + | CPrd (x, t1, t2) -> OpProd x, [|t1;t2|] + | CLam (x, t1, t2) -> OpLambda x, [|t1;t2|] + | CLet (x, b, t1, t2) -> OpLetIn x, [|b;t1;t2|] + | DOPN (AppL,a) -> OpAppL, a + | DOPN (Const sp, a) -> OpConst sp, a + | DOPN (Evar sp, a) -> OpEvar sp, a + | DOPN (MutInd ind_sp, l) -> OpMutInd ind_sp, l + | DOPN (MutConstruct cstr_sp,l) -> OpMutConstruct cstr_sp, l + | DOPN (MutCase ci,v) -> OpMutCase ci, v + | DOPN ((Fix (f,i),a)) as c -> + let (fi,(tl,lna,bl)) = destFix c in + OpRec (RFix fi,lna), Array.append tl bl + | DOPN ((CoFix i),a) as c -> + let (fi,(tl,lna,bl)) = destCoFix c in + OpRec (RCoFix fi,lna), Array.append tl bl | _ -> errorlabstrm "Term.splay_term" [< 'sTR "ill-formed constr" >] let gather_constr = function - | OpRel n, [] -> Rel n - | OpVar id, [] -> VAR id - | OpMeta n, [] -> DOP0 (Meta n) - | OpSort s, [] -> DOP0 (Sort s) - | OpCast, [t1;t2] -> DOP2 (Cast, t1, t2) - | OpProd x, [t1;t2] -> DOP2 (Prod, t1, (DLAM (x,t2))) - | OpLambda x, [t1;t2] -> DOP2 (Lambda, t1, (DLAM (x,t2))) - | OpAppL, a -> DOPN (AppL,Array.of_list a) - | OpConst sp, a -> DOPN (Const sp,Array.of_list a) - | OpEvar sp, a -> DOPN (Evar sp, Array.of_list a) - | OpMutInd ind_sp, l -> DOPN (MutInd ind_sp, Array.of_list l) - | OpMutConstruct cstr_sp, l -> DOPN (MutConstruct cstr_sp,Array.of_list l) - | OpMutCase ci, v -> DOPN (MutCase ci,Array.of_list v) - | OpRec (RFix (f,i)), a -> DOPN ((Fix (f,i),Array.of_list a)) - | OpRec (RCofix i), a -> DOPN ((CoFix i),Array.of_list a) + | OpRel n, [||] -> Rel n + | OpVar id, [||] -> VAR id + | OpMeta n, [||] -> DOP0 (Meta n) + | OpSort s, [||] -> DOP0 (Sort s) + | OpCast, [|t1;t2|] -> DOP2 (Cast, t1, t2) + | OpProd x, [|t1;t2|] -> mkProd (x, t1, t2) + | OpLambda x, [|t1;t2|] -> mkLambda (x, t1, t2) + | OpLetIn x, [|b;t1;t2|] -> mkLetIn (x, b, t1, t2) + | OpAppL, a -> DOPN (AppL, a) + | OpConst sp, a -> DOPN (Const sp, a) + | OpEvar sp, a -> DOPN (Evar sp, a) + | OpMutInd ind_sp, l -> DOPN (MutInd ind_sp, l) + | OpMutConstruct cstr_sp, l -> DOPN (MutConstruct cstr_sp, l) + | OpMutCase ci, v -> DOPN (MutCase ci, v) + | OpRec (RFix fi,lna), a -> + let n = Array.length a / 2 in + mkFix (fi,(Array.sub a 0 n, lna, Array.sub a n n)) + | OpRec (RCoFix i,lna), a -> + let n = Array.length a / 2 in + mkCoFix (i,(Array.sub a 0 n, lna, Array.sub a n n)) | _ -> errorlabstrm "Term.gather_term" [< 'sTR "ill-formed constr" >] + +let rec mycombine l1 l3 = + match (l1, l3) with + ([], []) -> [] + | (a1::l1, a3::l3) -> (a1, None, a3) :: mycombine l1 l3 + | (_, _) -> invalid_arg "mycombine" + +let rec mysplit = function + [] -> ([], []) + | (x, _, z)::l -> let (rx, rz) = mysplit l in (x::rx, z::rz) + +let splay_constr_with_binders = function + | Rel n -> OpRel n, [], [||] + | VAR id -> OpVar id, [], [||] + | DOP0 (Meta n) -> OpMeta n, [], [||] + | DOP0 (Sort s) -> OpSort s, [], [||] + | DOP2 (Cast, t1, t2) -> OpCast, [], [|t1;t2|] + | CPrd (x, t1, t2) -> OpProd x, [x,None,t1], [|t2|] + | CLam (x, t1, t2) -> OpLambda x, [x,None,t1], [|t2|] + | CLet (x, b, t1, t2) -> OpLetIn x, [x,Some b,t1], [|t2|] + | DOPN (AppL,a) -> OpAppL, [], a + | DOPN (Const sp, a) -> OpConst sp, [], a + | DOPN (Evar sp, a) -> OpEvar sp, [], a + | DOPN (MutInd ind_sp, l) -> OpMutInd ind_sp, [], l + | DOPN (MutConstruct cstr_sp,l) -> OpMutConstruct cstr_sp, [], l + | DOPN (MutCase ci,v) -> OpMutCase ci, [], v + | DOPN ((Fix (f,i),a)) as c -> + let (fi,(tl,lna,bl)) = destFix c in + let n = Array.length bl in + let ctxt = mycombine + (List.rev lna) + (Array.to_list (Array.mapi lift tl)) in + OpRec (RFix fi,lna), ctxt, bl + | DOPN ((CoFix i),a) as c -> + let (fi,(tl,lna,bl)) = destCoFix c in + let n = Array.length bl in + let ctxt = mycombine + (List.rev lna) + (Array.to_list (Array.mapi lift tl)) in + OpRec (RCoFix fi,lna), ctxt, bl + | _ -> errorlabstrm "Term.splay_term" [< 'sTR "ill-formed constr" >] + +let gather_constr_with_binders = function + | OpRel n, [], [||] -> Rel n + | OpVar id, [], [||] -> VAR id + | OpMeta n, [], [||] -> DOP0 (Meta n) + | OpSort s, [], [||] -> DOP0 (Sort s) + | OpCast, [], [|t1;t2|] -> DOP2 (Cast, t1, t2) + | OpProd _, [x,None,t1], [|t2|] -> mkProd (x, t1, t2) + | OpLambda _, [x,None,t1], [|t2|] -> mkLambda (x, t1, t2) + | OpLetIn _, [x,Some b,t1], [|t2|] -> mkLetIn (x, b, t1, t2) + | OpAppL, [], a -> DOPN (AppL, a) + | OpConst sp, [], a -> DOPN (Const sp, a) + | OpEvar sp, [], a -> DOPN (Evar sp, a) + | OpMutInd ind_sp, [], l -> DOPN (MutInd ind_sp, l) + | OpMutConstruct cstr_sp, [], l -> DOPN (MutConstruct cstr_sp, l) + | OpMutCase ci, [], v -> DOPN (MutCase ci, v) + | OpRec (RFix fi,lna), ctxt, bl -> + let (lna, tl) = mysplit ctxt in + let tl = Array.mapi (fun i -> lift (-i)) (Array.of_list tl) in + mkFix (fi,(tl, List.rev lna, bl)) + | OpRec (RCoFix i,lna), ctxt, bl -> + let (lna, tl) = mysplit ctxt in + let tl = Array.mapi (fun i -> lift (-i)) (Array.of_list tl) in + mkCoFix (i,(tl, List.rev lna, bl)) + | _ -> errorlabstrm "Term.gather_term" [< 'sTR "ill-formed constr" >] + +let generic_fold_left f acc bl tl = + let acc = + List.fold_left + (fun acc (_,bo,t) -> + match bo with + | None -> f acc t + | Some b -> f (f acc b) t) acc bl in + Array.fold_left f acc tl diff --git a/kernel/term.mli b/kernel/term.mli index cd86af675..0eb1d645d 100644 --- a/kernel/term.mli +++ b/kernel/term.mli @@ -2,11 +2,28 @@ (* $Id$ *) (*i*) +open Util open Pp open Names -open Generic +(*i open Generic i*) (*i*) +(*s The sorts of CCI. *) + +type contents = Pos | Null + +type sorts = + | Prop of contents (* Prop and Set *) + | Type of Univ.universe (* Type *) + +val str_of_contents : contents -> string +val contents_of_str : string -> contents + +val mk_Set : sorts +val mk_Prop : sorts + +val print_sort : sorts -> std_ppcmds + (*s The operators of the Calculus of Inductive Constructions. ['a] is the type of sorts. ([XTRA] is an extra slot, for putting in whatever sort of operator we need for whatever sort of application.) *) @@ -34,34 +51,32 @@ type 'a oper = | CoFix of int | XTRA of string -(*s The sorts of CCI. *) - -type contents = Pos | Null - -val str_of_contents : contents -> string -val contents_of_str : string -> contents - -type sorts = - | Prop of contents (* Prop and Set *) - | Type of Univ.universe (* Type *) - -val mk_Set : sorts -val mk_Prop : sorts - -val print_sort : sorts -> std_ppcmds - (*s The type [constr] of the terms of CCI - is obtained by instanciating the generic terms (type [term], - see \refsec{generic_terms}) on the above operators, themselves instanciated + is obtained by instanciating a generic notion of terms + on the above operators, themselves instanciated on the above sorts. *) -type constr = sorts oper term +(* [VAR] is used for named variables and [Rel] for variables as + de Bruijn indices. *) -type flat_arity = (name * constr) list * sorts +type constr = + | DOP0 of sorts oper + | DOP1 of sorts oper * constr + | DOP2 of sorts oper * constr * constr + | DOPN of sorts oper * constr array + | DLAM of name * constr + | DLAMV of name * constr array + | CLam of name * typed_type * constr + | CPrd of name * typed_type * constr + | CLet of name * constr * typed_type * constr + | VAR of identifier + | Rel of int + +and typed_type -(*type 'a judge = { body : constr; typ : 'a }*) +type flat_arity = (name * constr) list * sorts -type typed_type +(*s Functions about typed_type *) val make_typed : constr -> sorts -> typed_type val make_typed_lazy : constr -> (constr -> sorts) -> typed_type @@ -81,9 +96,9 @@ type var_declaration = identifier * constr option * typed_type type rel_declaration = name * constr option * typed_type (**********************************************************************) -type binder_kind = BProd | BLambda +type binder_kind = BProd | BLambda | BLetIn -type fix_kind = RFix of (int array * int) | RCofix of int +type fix_kind = RFix of (int array * int) | RCoFix of int type 'ctxt reference = | RConst of section_path * 'ctxt @@ -119,6 +134,7 @@ type kindOfTerm = | IsCast of constr * constr | IsProd of name * constr * constr | IsLambda of name * constr * constr + | IsLetIn of name * constr * constr * constr | IsAppL of constr * constr list | IsAbst of section_path * constr array | IsEvar of existential @@ -142,9 +158,6 @@ val kind_of_term : constr -> kindOfTerm (* Constructs a DeBrujin index *) val mkRel : int -> constr -(* Constructs an existential variable named "?" *) -val mkExistential : constr - (* Constructs an existential variable named "?n" *) val mkMeta : int -> constr @@ -172,15 +185,15 @@ val implicit_sort : sorts (* Constructs the term $t_1::t2$, i.e. the term $t_1$ casted with the type $t_2$ (that means t2 is declared as the type of t1). *) -val mkCast : constr -> constr -> constr +val mkCast : constr * constr -> constr (* Constructs the product $(x:t_1)t_2$ *) -val mkProd : name -> constr -> constr -> constr +val mkProd : name * constr * constr -> constr val mkNamedProd : identifier -> constr -> constr -> constr val mkProd_string : string -> constr -> constr -> constr (* Constructs the product $(x:t_1)t_2$ *) -val mkLetIn : name -> constr -> constr -> constr -> constr +val mkLetIn : name * constr * constr * constr -> constr val mkNamedLetIn : identifier -> constr -> constr -> constr -> constr (* Constructs either [(x:t)c] or [[x=b:t]c] *) @@ -199,7 +212,7 @@ val mkNamedProd_wo_LetIn : var_declaration -> constr -> constr val mkArrow : constr -> constr -> constr (* Constructs the abstraction $[x:t_1]t_2$ *) -val mkLambda : name -> constr -> constr -> constr +val mkLambda : name * constr * constr -> constr val mkNamedLambda : identifier -> constr -> constr -> constr (* [mkLambda_string s t c] constructs $[s:t]c$ *) @@ -230,7 +243,7 @@ val mkMutInd : inductive -> constr val mkMutConstruct : constructor -> constr (* Constructs the term <p>Case c of c1 | c2 .. | cn end *) -val mkMutCase : case_info -> constr -> constr -> constr list -> constr +val mkMutCase : case_info * constr * constr * constr list -> constr val mkMutCaseA : case_info -> constr -> constr -> constr array -> constr (* If [recindxs = [|i1,...in|]] @@ -238,7 +251,7 @@ val mkMutCaseA : case_info -> constr -> constr -> constr array -> constr [funnames = [f1,.....fn]] [bodies = [b1,.....bn]] then [ mkFix ((recindxs,i),typarray, funnames, bodies) ] - constructs the $i$th function of the block + constructs the $i$th function of the block (counting from 0) [Fixpoint f1 [ctx1] = b1 with f2 [ctx2] = b2 @@ -282,7 +295,7 @@ val destRel : constr -> int (* Destructs an existential variable *) val destMeta : constr -> int -val isMETA : constr -> bool +val isMeta : constr -> bool (* Destructs a variable *) val destVar : constr -> identifier @@ -330,6 +343,9 @@ val hd_is_constructor : constr -> bool (* Destructs the abstraction $[x:t_1]t_2$ *) val destLambda : constr -> name * constr * constr +(* Destructs the let $[x:=b:t_1]t_2$ *) +val destLetIn : constr -> name * constr * constr * constr + (* Destructs an application *) val destAppL : constr -> constr array val isAppL : constr -> bool @@ -339,6 +355,7 @@ val destApplication : constr -> constr * constr array (* Destructs a constant *) val destConst : constr -> section_path * constr array +val isConst : constr -> bool val path_of_const : constr -> section_path val args_of_const : constr -> constr array @@ -358,6 +375,7 @@ val args_of_mind : constr -> constr array (* Destructs a constructor *) val destMutConstruct : constr -> constructor +val isMutConstruct : constr -> bool val op_of_mconstr : constr -> constructor_path val args_of_mconstr : constr -> constr array @@ -541,6 +559,88 @@ val le_kind_implicit : constr -> constr -> bool val sort_hdchar : sorts -> string +(* Generic functions *) +val free_rels : constr -> Intset.t + +(* [closed0 M] is true iff [M] is a (deBruijn) closed term *) +val closed0 : constr -> bool + +(* [noccurn n M] returns true iff [Rel n] does NOT occur in term [M] *) +val noccurn : int -> constr -> bool + +(* [noccur_between n m M] returns true iff [Rel p] does NOT occur in term [M] + for n <= p < n+m *) +val noccur_between : int -> int -> constr -> bool + +(* Checking function for terms containing existential- or + meta-variables. The function [noccur_with_meta] considers only + meta-variable applied to some terms (intented to be its local + context) (for existential variables, it is necessarily the case) *) +val noccur_with_meta : int -> int -> constr -> bool + +(* [liftn n k c] lifts by [n] indexes above [k] in [c] *) +val liftn : int -> int -> constr -> constr + +(* [lift n c] lifts by [n] the positive indexes in [c] *) +val lift : int -> constr -> constr + +(* [pop c] lifts by -1 the positive indexes in [c] *) +val pop : constr -> constr + +(* [lift_context n ctxt] lifts terms in [ctxt] by [n] preserving + (i.e. not lifting) the internal references between terms of [ctxt]; + more recent terms come first in [ctxt] *) +val lift_context : int -> (name * constr) list -> (name * constr) list + +(* [substnl [a1;...;an] k c] substitutes in parallele [a1],...,[an] + for respectively [Rel(k+1)],...,[Rel(k+n)] in [c]; it relocates + accordingly indexes in [a1],...,[an] *) +val substnl : constr list -> int -> constr -> constr +val substl : constr list -> constr -> constr +val subst1 : constr -> constr -> constr + +(* [global_vars c] returns the list of [id]'s occurring as [VAR id] in [c] *) +val global_vars : constr -> identifier list + +val global_vars_set : constr -> Idset.t +val replace_vars : (identifier * constr) list -> constr -> constr +val subst_var : identifier -> constr -> constr + +(* [subst_vars [id1;...;idn] t] substitute [VAR idj] by [Rel j] in [t] + if two names are identical, the one of least indice is keeped *) +val subst_vars : identifier list -> constr -> constr + +(* [rel_list n m] and [rel_vect n m] compute [[Rel (n+m);...;Rel(n+1)]] *) +val rel_vect : int -> int -> constr array +val rel_list : int -> int -> constr list + +(*i************************************************************************i*) +(*i Pour Closure +(* Explicit substitutions of type ['a]. [ESID] = identity. + [CONS(t,S)] = $S.t$ i.e. parallel substitution. [SHIFT(n,S)] = + $(\uparrow n~o~S)$ i.e. terms in S are relocated with n vars. + [LIFT(n,S)] = $(\%n~S)$ stands for $((\uparrow n~o~S).n...1)$. *) +type 'a subs = + | ESID + | CONS of 'a * 'a subs + | SHIFT of int * 'a subs + | LIFT of int * 'a subs +val subs_cons : 'a * 'a subs -> 'a subs +val subs_liftn : int -> 'a subs -> 'a subs +val subs_lift : 'a subs -> 'a subs +val subs_shft : int * 'a subs -> 'a subs +val expand_rel : int -> 'a subs -> (int * 'a, int) union +i*) +(*s Lifts. [ELSHFT(l,n)] == lift of [n], then apply [lift l]. + [ELLFT(n,l)] == apply [l] to de Bruijn > [n] i.e under n binders. *) +type lift_spec = + | ELID + | ELSHFT of lift_spec * int + | ELLFT of int * lift_spec +val el_shft : int -> lift_spec -> lift_spec +val el_lift : lift_spec -> lift_spec +val reloc_rel: int -> lift_spec -> int +(*i*) (*s Occur check functions. *) @@ -550,7 +650,6 @@ val occur_meta : constr -> bool (*i val max_occur_meta : constr -> int i*) val occur_existential : constr -> bool -val rel_vect : int -> int -> constr array (* [(occur_const (s:section_path) c)] returns [true] if constant [s] occurs in c, [false] otherwise *) @@ -562,7 +661,7 @@ val occur_evar : existential_key -> constr -> bool (* [(occur_var id c)] returns [true] if variable [id] occurs free in c, [false] otherwise *) -val occur_var : identifier -> 'a term -> bool +val occur_var : identifier -> constr -> bool (* [dependent M N] is true iff M is eq\_constr with a subterm of N M is appropriately lifted through abstractions of N *) @@ -579,7 +678,6 @@ val eta_eq_constr : constr -> constr -> bool (*s The following functions substitutes [what] by [Rel 1] in [where] *) val subst_term : what:constr -> where:constr -> constr -val subst_term_eta_eq : what:constr -> where:constr -> constr val subst_term_occ : occs:int list -> what:constr -> where:constr -> constr val subst_term_occ_decl : occs:int list -> what:constr -> where:var_declaration -> var_declaration @@ -598,16 +696,26 @@ type constr_operator = | OpMeta of int | OpSort of sorts | OpRel of int | OpVar of identifier - | OpCast | OpProd of name | OpLambda of name + | OpCast | OpProd of name | OpLambda of name | OpLetIn of name | OpAppL | OpConst of section_path | OpAbst of section_path | OpEvar of existential_key | OpMutInd of inductive_path | OpMutConstruct of constructor_path | OpMutCase of case_info - | OpRec of fix_kind + | OpRec of fix_kind * Names.name list + +val splay_constr : constr -> constr_operator * constr array +val gather_constr : constr_operator * constr array -> constr + +val splay_constr_with_binders : constr -> + constr_operator * (name * constr option * constr) list * constr array +val gather_constr_with_binders : + constr_operator * (name * constr option * constr) list * constr array + -> constr -val splay_constr : constr -> constr_operator * constr list -val gather_constr : constr_operator * constr list -> constr +val generic_fold_left : + ('a -> constr -> 'a) -> 'a -> (name * constr option * constr) list + -> constr array -> 'a (*s Hash-consing functions for constr. *) diff --git a/kernel/type_errors.ml b/kernel/type_errors.ml index 518809392..34dee81c8 100644 --- a/kernel/type_errors.ml +++ b/kernel/type_errors.ml @@ -9,6 +9,24 @@ open Environ (* Type errors. *) +type guard_error = + (* Fixpoints *) + | NotEnoughAbstractionInFixBody + | RecursionNotOnInductiveType + | RecursionOnIllegalTerm + | NotEnoughArgumentsForFixCall + (* CoFixpoints *) + | CodomainNotInductiveType of constr + | NestedRecursiveOccurrences + | UnguardedRecursiveCall of constr + | RecCallInTypeOfAbstraction of constr + | RecCallInNonRecArgOfConstructor of constr + | RecCallInTypeOfDef of constr + | RecCallInCaseFun of constr + | RecCallInCaseArg of constr + | RecCallInCasePred of constr + | NotGuardedForm + type type_error = | UnboundRel of int | NotAType of unsafe_judgment @@ -24,7 +42,7 @@ type type_error = | CantApplyBadType of (int * constr * constr) * unsafe_judgment * unsafe_judgment list | CantApplyNonFunctional of unsafe_judgment * unsafe_judgment list - | IllFormedRecBody of std_ppcmds * name list * int * constr array + | IllFormedRecBody of guard_error * name list * int * constr array | IllTypedRecBody of int * name list * unsafe_judgment array * typed_type array | NotInductive of constr @@ -82,8 +100,8 @@ let error_cant_apply_not_functional k env rator randl = let error_cant_apply_bad_type k env sigma t rator randl = raise(TypeError (k, env_ise sigma env, CantApplyBadType (t,rator,randl))) -let error_ill_formed_rec_body k env str lna i vdefs = - raise (TypeError (k, env, IllFormedRecBody (str,lna,i,vdefs))) +let error_ill_formed_rec_body k env why lna i vdefs = + raise (TypeError (k, env, IllFormedRecBody (why,lna,i,vdefs))) let error_ill_typed_rec_body k env i lna vdefj vargs = raise (TypeError (k, env, IllTypedRecBody (i,lna,vdefj,vargs))) diff --git a/kernel/type_errors.mli b/kernel/type_errors.mli index 20fa410e4..f5e16f3c4 100644 --- a/kernel/type_errors.mli +++ b/kernel/type_errors.mli @@ -11,6 +11,26 @@ open Environ (* Type errors. \label{typeerrors} *) +(*i Rem: NotEnoughAbstractionInFixBody should only occur with "/i" Fix + notation i*) +type guard_error = + (* Fixpoints *) + | NotEnoughAbstractionInFixBody + | RecursionNotOnInductiveType + | RecursionOnIllegalTerm + | NotEnoughArgumentsForFixCall + (* CoFixpoints *) + | CodomainNotInductiveType of constr + | NestedRecursiveOccurrences + | UnguardedRecursiveCall of constr + | RecCallInTypeOfAbstraction of constr + | RecCallInNonRecArgOfConstructor of constr + | RecCallInTypeOfDef of constr + | RecCallInCaseFun of constr + | RecCallInCaseArg of constr + | RecCallInCasePred of constr + | NotGuardedForm + type type_error = | UnboundRel of int | NotAType of unsafe_judgment @@ -26,7 +46,7 @@ type type_error = | CantApplyBadType of (int * constr * constr) * unsafe_judgment * unsafe_judgment list | CantApplyNonFunctional of unsafe_judgment * unsafe_judgment list - | IllFormedRecBody of std_ppcmds * name list * int * constr array + | IllFormedRecBody of guard_error * name list * int * constr array | IllTypedRecBody of int * name list * unsafe_judgment array * typed_type array | NotInductive of constr @@ -80,8 +100,7 @@ val error_cant_apply_bad_type : unsafe_judgment -> unsafe_judgment list -> 'b val error_ill_formed_rec_body : - path_kind -> env -> std_ppcmds - -> name list -> int -> constr array -> 'b + path_kind -> env -> guard_error -> name list -> int -> constr array -> 'b val error_ill_typed_rec_body : path_kind -> env -> int -> name list -> unsafe_judgment array diff --git a/kernel/typeops.ml b/kernel/typeops.ml index 4077d852f..4b22b0b6a 100644 --- a/kernel/typeops.ml +++ b/kernel/typeops.ml @@ -5,7 +5,7 @@ open Pp open Util open Names open Univ -open Generic +(*i open Generic i*) open Term open Declarations open Sign @@ -113,17 +113,17 @@ let type_of_existential env sigma c = (* Case. *) let rec mysort_of_arity env sigma c = - match whd_betadeltaiota env sigma c with - | DOP0(Sort(s)) -> s - | DOP2(Prod,_,DLAM(_,c2)) -> mysort_of_arity env sigma c2 + match kind_of_term (whd_betadeltaiota env sigma c) with + | IsSort s -> s + | IsProd(_,_,c2) -> mysort_of_arity env sigma c2 | _ -> invalid_arg "mysort_of_arity" let error_elim_expln env sigma kp ki = - if is_info_sort env sigma kp && not (is_info_sort env sigma ki) then + if is_info_arity env sigma kp && not (is_info_arity env sigma ki) then "non-informative objects may not construct informative ones." else - match (kp,ki) with - | (DOP0(Sort (Type _)), DOP0(Sort (Prop _))) -> + match (kind_of_term kp,kind_of_term ki) with + | IsSort (Type _), IsSort (Prop _) -> "strong elimination on non-small inductive types leads to paradoxes." | _ -> "wrong arity" @@ -131,13 +131,15 @@ exception Arity of (constr * constr * string) option let is_correct_arity env sigma kelim (c,p) indf (pt,t) = let rec srec (pt,t) = - match whd_betadeltaiota env sigma pt, whd_betadeltaiota env sigma t with - | DOP2(Prod,a1,DLAM(_,a2)), DOP2(Prod,a1',DLAM(_,a2')) -> + let pt' = whd_betadeltaiota env sigma pt in + let t' = whd_betadeltaiota env sigma t in + match kind_of_term pt', kind_of_term t' with + | IsProd (_,a1,a2), IsProd (_,a1',a2') -> if is_conv env sigma a1 a1' then srec (a2,a2') else raise (Arity None) - | DOP2(Prod,a1,DLAM(_,a2)), ki -> + | IsProd (_,a1,a2), _ -> let k = whd_betadeltaiota env sigma a2 in let ksort = (match k with DOP0(Sort s) -> s | _ -> raise (Arity None)) in @@ -146,18 +148,18 @@ let is_correct_arity env sigma kelim (c,p) indf (pt,t) = if List.exists (base_sort_cmp CONV ksort) kelim then (true,k) else - raise (Arity (Some(k,ki,error_elim_expln env sigma k ki))) + raise (Arity (Some(k,t',error_elim_expln env sigma k t'))) else raise (Arity None) - | k, DOP2(Prod,_,_) -> + | k, IsProd (_,_,_) -> raise (Arity None) | k, ki -> - let ksort = (match k with DOP0(Sort s) -> s + let ksort = (match k with IsSort s -> s | _ -> raise (Arity None)) in if List.exists (base_sort_cmp CONV ksort) kelim then - false,k + false, pt' else - raise (Arity (Some(k,ki,error_elim_expln env sigma k ki))) + raise (Arity (Some(pt',t',error_elim_expln env sigma pt' t'))) in try srec (pt,t) with Arity kinds -> @@ -274,12 +276,13 @@ let typed_product env name var c = let rcst = ref Constraint.empty in let hacked_sort_of_product s1 s2 = let (s,cst) = sort_of_product s1 s2 (universes env) in (rcst:=cst; s) in - typed_combine (mkProd name) hacked_sort_of_product var c, !rcst + typed_combine (fun c t -> mkProd (name,c,t)) hacked_sort_of_product var c, + !rcst let abs_rel env sigma name var j = let cvar = incast_type var in let typ,cst = typed_product env name var j.uj_type in - { uj_val = mkLambda name cvar j.uj_val; + { uj_val = mkLambda (name, cvar, j.uj_val); uj_type = typ }, cst @@ -292,7 +295,7 @@ let gen_rel env sigma name varj j = let (s',g) = sort_of_product varj.utj_type s (universes env) in let res_type = mkSort s' in let (res_kind,g') = type_of_sort res_type in - { uj_val = mkProd name (incast_type var) j.uj_val; + { uj_val = mkProd (name, incast_type var, j.uj_val); uj_type = make_typed res_type res_kind }, g' | _ -> @@ -321,8 +324,8 @@ let apply_rel_list env sigma nocheck argjl funj = uj_type = typed_app (fun _ -> typ) funj.uj_type }, cst | hj::restjl -> - match whd_betadeltaiota env sigma typ with - | DOP2(Prod,c1,DLAM(_,c2)) -> + match kind_of_term (whd_betadeltaiota env sigma typ) with + | IsProd (_,c1,c2) -> if nocheck then apply_rec (n+1) (subst1 hj.uj_val c2) cst restjl else @@ -342,33 +345,6 @@ let apply_rel_list env sigma nocheck argjl funj = (* Fixpoints. *) -(* Checking function for terms containing existential variables. - The function [noccur_with_meta] considers the fact that - each existential variable (as well as each isevar) - in the term appears applied to its local context, - which may contain the CoFix variables. These occurrences of CoFix variables - are not considered *) - -exception Occur -let noccur_with_meta n m term = - let rec occur_rec n = function - | Rel p -> if n<=p & p<n+m then raise Occur - | VAR _ -> () - | DOPN(AppL,cl) -> - (match strip_outer_cast cl.(0) with - | DOP0 (Meta _) -> () - | _ -> Array.iter (occur_rec n) cl) - | DOPN(Evar _, _) -> () - | DOPN(op,cl) -> Array.iter (occur_rec n) cl - | DOPL(_,cl) -> List.iter (occur_rec n) cl - | DOP0(_) -> () - | DOP1(_,c) -> occur_rec n c - | DOP2(_,c1,c2) -> occur_rec n c1; occur_rec n c2 - | DLAM(_,c) -> occur_rec (n+1) c - | DLAMV(_,v) -> Array.iter (occur_rec (n+1)) v - in - try (occur_rec n term; true) with Occur -> false - (* Check if t is a subterm of Rel n, and gives its specification, assuming lst already gives index of subterms with corresponding specifications of recursive arguments *) @@ -396,17 +372,17 @@ let rec instantiate_recarg sp lrc ra = (* propagate checking for F,incorporating recursive arguments *) let check_term env mind_recvec f = let rec crec n l (lrec,c) = - match (lrec,strip_outer_cast c) with - | (Param(_)::lr,DOP2(Lambda,_,DLAM(_,b))) -> + match lrec, kind_of_term (strip_outer_cast c) with + | (Param(_)::lr, IsLambda (_,_,b)) -> let l' = map_lift_fst l in crec (n+1) l' (lr,b) - | (Norec::lr,DOP2(Lambda,_,DLAM(_,b))) -> + | (Norec::lr, IsLambda (_,_,b)) -> let l' = map_lift_fst l in crec (n+1) l' (lr,b) - | (Mrec(i)::lr,DOP2(Lambda,_,DLAM(_,b))) -> + | (Mrec(i)::lr, IsLambda (_,_,b)) -> let l' = map_lift_fst l in crec (n+1) ((1,mind_recvec.(i))::l') (lr,b) - | (Imbr((sp,i) as ind_sp,lrc)::lr,DOP2(Lambda,_,DLAM(_,b))) -> + | (Imbr((sp,i) as ind_sp,lrc)::lr, IsLambda (_,_,b)) -> let l' = map_lift_fst l in let sprecargs = mis_recargs (lookup_mind_specif (ind_sp,[||]) env) in @@ -414,7 +390,7 @@ let check_term env mind_recvec f = Array.map (List.map (instantiate_recarg sp lrc)) sprecargs.(i) in crec (n+1) ((1,lc)::l') (lr,b) - | _,f_0 -> f n l f_0 + | _,_ -> f n l (strip_outer_cast c) in crec @@ -425,28 +401,28 @@ let is_inst_var env sigma k c = let is_subterm_specif env sigma lcx mind_recvec = let rec crec n lst c = - match whd_betadeltaiota_stack env sigma c [] with - | ((Rel k),_) -> find_sorted_assoc k lst - | (DOPN(MutCase _,_) as x,_) -> - let ( _,_,c,br) = destCase x in - if Array.length br = 0 then - [||] - else - let lcv = - (try - if is_inst_var env sigma n c then lcx else (crec n lst c) - with Not_found -> (Array.create (Array.length br) [])) - in - assert (Array.length br = Array.length lcv); - let stl = - array_map2 - (fun lc a -> - check_term env mind_recvec crec n lst (lc,a)) lcv br - in - stl.(0) + let f,l = whd_betadeltaiota_stack env sigma c [] in + match kind_of_term f with + | IsRel k -> find_sorted_assoc k lst + + | IsMutCase ( _,_,c,br) -> + if Array.length br = 0 then + [||] + else + let lcv = + (try + if is_inst_var env sigma n c then lcx else (crec n lst c) + with Not_found -> (Array.create (Array.length br) [])) + in + assert (Array.length br = Array.length lcv); + let stl = + array_map2 + (fun lc a -> + check_term env mind_recvec crec n lst (lc,a)) lcv br + in + stl.(0) - | (DOPN(Fix(_),la) as mc,l) -> - let ((recindxs,i),(typarray,funnames,bodies)) = destFix mc in + | IsFix ((recindxs,i),(typarray,funnames,bodies)) -> let nbfix = List.length funnames in let decrArg = recindxs.(i) in let theBody = bodies.(i) in @@ -470,12 +446,12 @@ let is_subterm_specif env sigma lcx mind_recvec = in crec (n+nbOfAbst) newlst strippedBody - | (DOP2(Lambda,_,DLAM(_,b)),[]) -> - let lst' = map_lift_fst lst in - crec (n+1) lst' b + | IsLambda (_,_,b) when l=[] -> + let lst' = map_lift_fst lst in + crec (n+1) lst' b (*** Experimental change *************************) - | (DOP0(Meta _),_) -> [||] + | IsMeta _ -> [||] | _ -> raise Not_found in crec @@ -486,26 +462,29 @@ let is_subterm env sigma lcx mind_recvec n lst c = with Not_found -> false +exception FixGuardError of guard_error + (* Auxiliary function: it checks a condition f depending on a deBrujin index for a certain number of abstractions *) -let rec check_subterm_rec_meta env sigma vectn k def = +let rec check_subterm_rec_meta env sigma vectn k def = + (* If k<0, it is a general fixpoint *) (k < 0) or (let nfi = Array.length vectn in (* check fi does not appear in the k+1 first abstractions, gives the type of the k+1-eme abstraction *) let rec check_occur n def = - (match strip_outer_cast def with - | DOP2(Lambda,a,DLAM(_,b)) -> - if noccur_with_meta n nfi a then - if n = k+1 then (a,b) else check_occur (n+1) b - else - error "Bad occurrence of recursive call" - | _ -> error "Not enough abstractions in the definition") in + match kind_of_term (strip_outer_cast def) with + | IsLambda (_,a,b) -> + if noccur_with_meta n nfi a then + if n = k+1 then (a,b) else check_occur (n+1) b + else + anomaly "check_subterm_rec_meta: Bad occurrence of recursive call" + | _ -> raise (FixGuardError NotEnoughAbstractionInFixBody) in let (c,d) = check_occur 1 def in let ((sp,tyi),_ as mind, largs) = - (try find_minductype env sigma c - with Induc -> error "Recursive definition on a non inductive type") in + try find_minductype env sigma c + with Induc -> raise (FixGuardError RecursionNotOnInductiveType) in let mind_recvec = mis_recargs (lookup_mind_specif mind env) in let lcx = mind_recvec.(tyi) in (* n = decreasing argument in the definition; @@ -516,8 +495,9 @@ let rec check_subterm_rec_meta env sigma vectn k def = (* n gives the index of the recursive variable *) (noccur_with_meta (n+k+1) nfi t) or (* no recursive call in the term *) - (match whd_betadeltaiota_stack env sigma t [] with - | (Rel p,l) -> + (let f,l = whd_betadeltaiota_stack env sigma t [] in + match kind_of_term f with + | IsRel p -> if n+k+1 <= p & p < n+k+nfi+1 then (* recursive call *) let glob = nfi+n+k-p in (* the index of the recursive call *) @@ -527,12 +507,12 @@ let rec check_subterm_rec_meta env sigma vectn k def = (la,(z::lrest)) -> if (is_subterm env sigma lcx mind_recvec n lst z) then List.for_all (check_rec_call n lst) (la@lrest) - else error "Recursive call applied to an illegal term" + else raise (FixGuardError RecursionOnIllegalTerm) | _ -> assert false) - else error "Not enough arguments for the recursive call" + else raise (FixGuardError NotEnoughArgumentsForFixCall) else List.for_all (check_rec_call n lst) l - | (DOPN(MutCase _,_) as mc,l) -> - let (ci,p,c_0,lrest) = destCase mc in + + | IsMutCase (ci,p,c_0,lrest) -> let lc = (try if is_inst_var env sigma n c_0 then @@ -563,13 +543,16 @@ let rec check_subterm_rec_meta env sigma vectn k def = Eduardo 7/9/98 *) - | (DOPN(Fix(_),la) as mc,l) -> + | IsFix ((recindxs,i),(typarray,funnames,bodies)) -> (List.for_all (check_rec_call n lst) l) && - let ((recindxs,i),(typarray,funnames,bodies)) = destFix mc in let nbfix = List.length funnames in let decrArg = recindxs.(i) in if (List.length l < (decrArg+1)) then - (array_for_all (check_rec_call n lst) la) + (array_for_all (check_rec_call n lst) typarray) + && + (array_for_all + (check_rec_call (n+nbfix) (map_lift_fst_n nbfix lst)) + bodies) else let theDecrArg = List.nth l decrArg in let recArgsDecrArg = @@ -579,7 +562,11 @@ let rec check_subterm_rec_meta env sigma vectn k def = Array.create 0 [] in if (Array.length recArgsDecrArg)=0 then - array_for_all (check_rec_call n lst) la + (array_for_all (check_rec_call n lst) typarray) + && + (array_for_all + (check_rec_call (n+nbfix) (map_lift_fst_n nbfix lst)) + bodies) else let theBody = bodies.(i) in let (gamma,strippedBody) = @@ -594,29 +581,63 @@ let rec check_subterm_rec_meta env sigma vectn k def = typarray) && (list_for_all_i (fun n -> check_rec_call n lst) n absTypes) & (check_rec_call (n+nbOfAbst) newlst strippedBody)) - - - | (DOP2(_,a,b),l) -> + + | IsCast (a,b) -> (check_rec_call n lst a) && (check_rec_call n lst b) && (List.for_all (check_rec_call n lst) l) - | (DOPN(_,la),l) -> - (array_for_all (check_rec_call n lst) la) && - (List.for_all (check_rec_call n lst) l) + | IsLambda (_,a,b) -> + (check_rec_call n lst a) && + (check_rec_call (n+1) (map_lift_fst lst) b) && + (List.for_all (check_rec_call n lst) l) + + | IsProd (_,a,b) -> + (check_rec_call n lst a) && + (check_rec_call (n+1) (map_lift_fst lst) b) && + (List.for_all (check_rec_call n lst) l) - | (DOP0 (Meta _),l) -> true + | IsLetIn (_,a,b,c) -> + (check_rec_call n lst a) && + (check_rec_call n lst b) && + (check_rec_call (n+1) (map_lift_fst lst) c) && + (List.for_all (check_rec_call n lst) l) - | (DLAM(_,t),l) -> - (check_rec_call (n+1) (map_lift_fst lst) t) && + | IsMutInd (_,la) -> + (array_for_all (check_rec_call n lst) la) && (List.for_all (check_rec_call n lst) l) - | (DLAMV(_,vt),l) -> - (array_for_all (check_rec_call (n+1) (map_lift_fst lst)) vt) && + | IsMutConstruct (_,la) -> + (array_for_all (check_rec_call n lst) la) && (List.for_all (check_rec_call n lst) l) - | (_,l) -> List.for_all (check_rec_call n lst) l - ) + | IsConst (_,la) -> + (array_for_all (check_rec_call n lst) la) && + (List.for_all (check_rec_call n lst) l) + + | IsAppL (f,la) -> + (check_rec_call n lst f) && + (List.for_all (check_rec_call n lst) la) && + (List.for_all (check_rec_call n lst) l) + + | IsCoFix (i,(typarray,funnames,bodies)) -> + let nbfix = Array.length bodies in + (array_for_all (check_rec_call n lst) typarray) && + (List.for_all (check_rec_call n lst) l) && + (array_for_all + (check_rec_call (n+nbfix) (map_lift_fst_n nbfix lst)) + bodies) + + | IsEvar (_,la) -> + (array_for_all (check_rec_call n lst) la) && + (List.for_all (check_rec_call n lst) l) + + | IsMeta _ -> true + + | IsVar _ | IsSort _ -> List.for_all (check_rec_call n lst) l + + | IsXtra _ | IsAbst _ -> List.for_all (check_rec_call n lst) l + ) in check_rec_call 1 [] d) @@ -633,25 +654,30 @@ let check_fix env sigma ((nvect,bodynum),(types,names,bodies)) = or Array.length nvect <> nbfix or Array.length types <> nbfix or List.length names <> nbfix - then error "Ill-formed fix term"; + or bodynum < 0 + or bodynum >= nbfix + then anomaly "Ill-formed fix term"; for i = 0 to nbfix - 1 do try let _ = check_subterm_rec_meta env sigma nvect nvect.(i) bodies.(i) in () - with UserError (s,str) -> - error_ill_formed_rec_body CCI env str (List.rev names) i bodies + with FixGuardError err -> + error_ill_formed_rec_body CCI env err (List.rev names) i bodies done (* Co-fixpoints. *) +exception CoFixGuardError of guard_error + let check_guard_rec_meta env sigma nbfix def deftype = let rec codomain_is_coind c = - match whd_betadeltaiota env sigma (strip_outer_cast c) with - | DOP2(Prod,a,DLAM(_,b)) -> codomain_is_coind b - | b -> - (try find_mcoinductype env sigma b - with - | Induc -> error "The codomain is not a coinductive type" -(* | _ -> error "Type of Cofix function not as expected") ??? *) ) + let b = whd_betadeltaiota env sigma (strip_outer_cast c) in + match kind_of_term b with + | IsProd (_,a,b) -> codomain_is_coind b + | _ -> + try + find_mcoinductype env sigma b + with Induc -> + raise (CoFixGuardError (CodomainNotInductiveType b)) in let (mind, _) = codomain_is_coind deftype in let ((sp,tyi),_) = mind in @@ -671,11 +697,11 @@ let check_guard_rec_meta env sigma nbfix def deftype = if List.for_all (noccur_with_meta n nbfix) l then true else - error "Nested recursive occurrences" + raise (CoFixGuardError NestedRecursiveOccurrences) else - error "Unguarded recursive call" + raise (CoFixGuardError (UnguardedRecursiveCall t)) else - error "check_guard_rec_meta: ???" + error "check_guard_rec_meta: ???" (* ??? *) | (DOPN (MutConstruct(_,i as cstr_sp),l), args) -> let lra =vlra.(i-1) in @@ -710,7 +736,8 @@ let check_guard_rec_meta env sigma nbfix def deftype = | _::lrar -> if (noccur_with_meta n nbfix t) then (process_args_of_constr lr lrar) - else error "Recursive call inside a non-recursive argument of constructor") + else raise (CoFixGuardError + (RecCallInNonRecArgOfConstructor t))) in (process_args_of_constr realargs lra) @@ -718,7 +745,7 @@ let check_guard_rec_meta env sigma nbfix def deftype = if (noccur_with_meta n nbfix a) then check_rec_call alreadygrd (n+1) vlra b else - error "Recursive call in the type of an abstraction" + raise (CoFixGuardError (RecCallInTypeOfAbstraction t)) | (DOPN(CoFix(j),vargs) as cofix,l) -> if (List.for_all (noccur_with_meta n nbfix) l) @@ -730,8 +757,9 @@ let check_guard_rec_meta env sigma nbfix def deftype = && (List.for_all (check_rec_call alreadygrd (n+1) vlra) l) else - error "Recursive call in the type of a declaration" - else error "Unguarded recursive call" + raise (CoFixGuardError (RecCallInTypeOfDef cofix)) + else + raise (CoFixGuardError (UnguardedRecursiveCall cofix)) | (DOPN(MutCase _,_) as mc,l) -> let (_,p,c,vrest) = destCase mc in @@ -740,13 +768,13 @@ let check_guard_rec_meta env sigma nbfix def deftype = if (List.for_all (noccur_with_meta n nbfix) l) then (array_for_all (check_rec_call alreadygrd n vlra) vrest) else - error "Recursive call in the argument of a function defined by cases" + raise (CoFixGuardError (RecCallInCaseFun mc)) else - error "Recursive call in the argument of a case expression" + raise (CoFixGuardError (RecCallInCaseArg mc)) else - error "Recursive call in the type of a Case expression" + raise (CoFixGuardError (RecCallInCasePred mc)) - | _ -> error "Definition not in guarded form" + | _ -> raise (CoFixGuardError NotGuardedForm) in check_rec_call false 1 vlra def @@ -758,11 +786,9 @@ let check_cofix env sigma (bodynum,(types,names,bodies)) = let nbfix = Array.length bodies in for i = 0 to nbfix-1 do try - let _ = - check_guard_rec_meta env sigma nbfix bodies.(i) types.(i) in - () - with UserError (s,str) -> - error_ill_formed_rec_body CCI env str (List.rev names) i bodies + let _ = check_guard_rec_meta env sigma nbfix bodies.(i) types.(i) in () + with CoFixGuardError err -> + error_ill_formed_rec_body CCI env err (List.rev names) i bodies done (* let check_cofix env sigma f = @@ -814,22 +840,28 @@ let type_fixpoint env sigma lna lar vdefj = syntaxic conditions *) let control_only_guard env sigma = - let rec control_rec = function - | Rel(p) -> () - | VAR _ -> () - | DOP0(_) -> () - | DOPN(CoFix(_),cl) as cofix -> - check_cofix env sigma (destCoFix cofix); - Array.iter control_rec cl - | DOPN(Fix(_),cl) as fix -> - check_fix env sigma (destFix fix); - Array.iter control_rec cl - | DOPN(_,cl) -> Array.iter control_rec cl - | DOPL(_,cl) -> List.iter control_rec cl - | DOP1(_,c) -> control_rec c - | DOP2(_,c1,c2) -> control_rec c1; control_rec c2 - | DLAM(_,c) -> control_rec c - | DLAMV(_,v) -> Array.iter control_rec v + let rec control_rec c = match kind_of_term c with + | IsRel _ | IsVar _ -> () + | IsSort _ | IsMeta _ | IsXtra _ -> () + | IsCoFix (_,(tys,_,bds) as cofix) -> + check_cofix env sigma cofix; + Array.iter control_rec tys; + Array.iter control_rec bds; + | IsFix (_,(tys,_,bds) as fix) -> + check_fix env sigma fix; + Array.iter control_rec tys; + Array.iter control_rec bds; + | IsMutCase(_,p,c,b) ->control_rec p;control_rec c;Array.iter control_rec b + | IsMutInd (_,cl) -> Array.iter control_rec cl + | IsMutConstruct (_,cl) -> Array.iter control_rec cl + | IsConst (_,cl) -> Array.iter control_rec cl + | IsEvar (_,cl) -> Array.iter control_rec cl + | IsAbst (_,cl) -> Array.iter control_rec cl + | IsAppL (_,cl) -> List.iter control_rec cl + | IsCast (c1,c2) -> control_rec c1; control_rec c2 + | IsProd (_,c1,c2) -> control_rec c1; control_rec c2 + | IsLambda (_,c1,c2) -> control_rec c1; control_rec c2 + | IsLetIn (_,c1,c2,c3) -> control_rec c1; control_rec c2; control_rec c3 in control_rec |