summaryrefslogtreecommitdiff
path: root/kernel/closure.ml
diff options
context:
space:
mode:
authorGravatar Enrico Tassi <gareuselesinge@debian.org>2016-12-27 16:53:30 +0100
committerGravatar Enrico Tassi <gareuselesinge@debian.org>2016-12-27 18:33:25 +0100
commit1b92c226e563643da187b8614d5888dc4855eb43 (patch)
treec4c3d204b36468b58cb71050ba95f06b8dd7bc2e /kernel/closure.ml
parent7c9b0a702976078b813e6493c1284af62a3f093c (diff)
Imported Upstream version 8.6
Diffstat (limited to 'kernel/closure.ml')
-rw-r--r--kernel/closure.ml1058
1 files changed, 0 insertions, 1058 deletions
diff --git a/kernel/closure.ml b/kernel/closure.ml
deleted file mode 100644
index 2ba80d83..00000000
--- a/kernel/closure.ml
+++ /dev/null
@@ -1,1058 +0,0 @@
-(************************************************************************)
-(* v * The Coq Proof Assistant / The Coq Development Team *)
-(* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2016 *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(************************************************************************)
-
-(* Created by Bruno Barras with Benjamin Werner's account to implement
- a call-by-value conversion algorithm and a lazy reduction machine
- with sharing, Nov 1996 *)
-(* Addition of zeta-reduction (let-in contraction) by Hugo Herbelin, Oct 2000 *)
-(* Call-by-value machine moved to cbv.ml, Mar 01 *)
-(* Additional tools for module subtyping by Jacek Chrzaszcz, Aug 2002 *)
-(* Extension with closure optimization by Bruno Barras, Aug 2003 *)
-(* Support for evar reduction by Bruno Barras, Feb 2009 *)
-(* Miscellaneous other improvements by Bruno Barras, 1997-2009 *)
-
-(* This file implements a lazy reduction for the Calculus of Inductive
- Constructions *)
-
-open Errors
-open Util
-open Pp
-open Names
-open Term
-open Vars
-open Environ
-open Esubst
-
-let stats = ref false
-let share = ref true
-
-(* Profiling *)
-let beta = ref 0
-let delta = ref 0
-let eta = ref 0
-let zeta = ref 0
-let evar = ref 0
-let iota = ref 0
-let prune = ref 0
-
-let reset () =
- beta := 0; delta := 0; zeta := 0; evar := 0; iota := 0; evar := 0;
- prune := 0
-
-let stop() =
- msg_debug (str "[Reds: beta=" ++ int !beta ++ str" delta=" ++ int !delta ++
- str " eta=" ++ int !eta ++ str" zeta=" ++ int !zeta ++ str" evar=" ++
- int !evar ++ str" iota=" ++ int !iota ++ str" prune=" ++ int !prune ++
- str"]")
-
-let incr_cnt red cnt =
- if red then begin
- if !stats then incr cnt;
- true
- end else
- false
-
-let with_stats c =
- if !stats then begin
- reset();
- let r = Lazy.force c in
- stop();
- r
- end else
- Lazy.force c
-
-let all_opaque = (Id.Pred.empty, Cpred.empty)
-let all_transparent = (Id.Pred.full, Cpred.full)
-
-let is_transparent_variable (ids, _) id = Id.Pred.mem id ids
-let is_transparent_constant (_, csts) cst = Cpred.mem cst csts
-
-module type RedFlagsSig = sig
- type reds
- type red_kind
- val fBETA : red_kind
- val fDELTA : red_kind
- val fETA : red_kind
- val fIOTA : red_kind
- val fZETA : red_kind
- val fCONST : constant -> red_kind
- val fVAR : Id.t -> red_kind
- val no_red : reds
- val red_add : reds -> red_kind -> reds
- val red_sub : reds -> red_kind -> reds
- val red_add_transparent : reds -> transparent_state -> reds
- val mkflags : red_kind list -> reds
- val red_set : reds -> red_kind -> bool
- val red_projection : reds -> projection -> bool
-end
-
-module RedFlags = (struct
-
- (* [r_const=(true,cl)] means all constants but those in [cl] *)
- (* [r_const=(false,cl)] means only those in [cl] *)
- (* [r_delta=true] just mean [r_const=(true,[])] *)
-
- type reds = {
- r_beta : bool;
- r_delta : bool;
- r_eta : bool;
- r_const : transparent_state;
- r_zeta : bool;
- r_iota : bool }
-
- type red_kind = BETA | DELTA | ETA | IOTA | ZETA
- | CONST of constant | VAR of Id.t
- let fBETA = BETA
- let fDELTA = DELTA
- let fETA = ETA
- let fIOTA = IOTA
- let fZETA = ZETA
- let fCONST kn = CONST kn
- let fVAR id = VAR id
- let no_red = {
- r_beta = false;
- r_delta = false;
- r_eta = false;
- r_const = all_opaque;
- r_zeta = false;
- r_iota = false }
-
- let red_add red = function
- | BETA -> { red with r_beta = true }
- | ETA -> { red with r_eta = true }
- | DELTA -> { red with r_delta = true; r_const = all_transparent }
- | CONST kn ->
- let (l1,l2) = red.r_const in
- { red with r_const = l1, Cpred.add kn l2 }
- | IOTA -> { red with r_iota = true }
- | ZETA -> { red with r_zeta = true }
- | VAR id ->
- let (l1,l2) = red.r_const in
- { red with r_const = Id.Pred.add id l1, l2 }
-
- let red_sub red = function
- | BETA -> { red with r_beta = false }
- | ETA -> { red with r_eta = false }
- | DELTA -> { red with r_delta = false }
- | CONST kn ->
- let (l1,l2) = red.r_const in
- { red with r_const = l1, Cpred.remove kn l2 }
- | IOTA -> { red with r_iota = false }
- | ZETA -> { red with r_zeta = false }
- | VAR id ->
- let (l1,l2) = red.r_const in
- { red with r_const = Id.Pred.remove id l1, l2 }
-
- let red_add_transparent red tr =
- { red with r_const = tr }
-
- let mkflags = List.fold_left red_add no_red
-
- let red_set red = function
- | BETA -> incr_cnt red.r_beta beta
- | ETA -> incr_cnt red.r_eta eta
- | CONST kn ->
- let (_,l) = red.r_const in
- let c = Cpred.mem kn l in
- incr_cnt c delta
- | VAR id -> (* En attendant d'avoir des kn pour les Var *)
- let (l,_) = red.r_const in
- let c = Id.Pred.mem id l in
- incr_cnt c delta
- | ZETA -> incr_cnt red.r_zeta zeta
- | IOTA -> incr_cnt red.r_iota iota
- | DELTA -> (* Used for Rel/Var defined in context *)
- incr_cnt red.r_delta delta
-
- let red_projection red p =
- if Projection.unfolded p then true
- else red_set red (fCONST (Projection.constant p))
-
-end : RedFlagsSig)
-
-open RedFlags
-
-let betadeltaiota = mkflags [fBETA;fDELTA;fZETA;fIOTA]
-let betadeltaiotanolet = mkflags [fBETA;fDELTA;fIOTA]
-let betaiota = mkflags [fBETA;fIOTA]
-let beta = mkflags [fBETA]
-let betaiotazeta = mkflags [fBETA;fIOTA;fZETA]
-
-(* Removing fZETA for finer behaviour would break many developments *)
-let unfold_side_flags = [fBETA;fIOTA;fZETA]
-let unfold_side_red = mkflags [fBETA;fIOTA;fZETA]
-let unfold_red kn =
- let flag = match kn with
- | EvalVarRef id -> fVAR id
- | EvalConstRef kn -> fCONST kn in
- mkflags (flag::unfold_side_flags)
-
-(* Flags of reduction and cache of constants: 'a is a type that may be
- * mapped to constr. 'a infos implements a cache for constants and
- * abstractions, storing a representation (of type 'a) of the body of
- * this constant or abstraction.
- * * i_tab is the cache table of the results
- * * i_repr is the function to get the representation from the current
- * state of the cache and the body of the constant. The result
- * is stored in the table.
- * * i_rels is the array of free rel variables together with their optional
- * body
- *
- * ref_value_cache searchs in the tab, otherwise uses i_repr to
- * compute the result and store it in the table. If the constant can't
- * be unfolded, returns None, but does not store this failure. * This
- * doesn't take the RESET into account. You mustn't keep such a table
- * after a Reset. * This type is not exported. Only its two
- * instantiations (cbv or lazy) are.
- *)
-
-type table_key = constant puniverses tableKey
-
-let eq_pconstant_key (c,u) (c',u') =
- eq_constant_key c c' && Univ.Instance.equal u u'
-
-module IdKeyHash =
-struct
- open Hashset.Combine
- type t = table_key
- let equal = Names.eq_table_key eq_pconstant_key
- let hash = function
- | ConstKey (c, _) -> combinesmall 1 (Constant.UserOrd.hash c)
- | VarKey id -> combinesmall 2 (Id.hash id)
- | RelKey i -> combinesmall 3 (Int.hash i)
-end
-
-module KeyTable = Hashtbl.Make(IdKeyHash)
-
-let eq_table_key = IdKeyHash.equal
-
-type 'a infos_cache = {
- i_repr : 'a infos -> constr -> 'a;
- i_env : env;
- i_sigma : existential -> constr option;
- i_rels : constr option array;
- i_tab : 'a KeyTable.t }
-
-and 'a infos = {
- i_flags : reds;
- i_cache : 'a infos_cache }
-
-let info_flags info = info.i_flags
-let info_env info = info.i_cache.i_env
-
-let rec assoc_defined id = function
-| [] -> raise Not_found
-| (_, None, _) :: ctxt -> assoc_defined id ctxt
-| (id', Some c, _) :: ctxt ->
- if Id.equal id id' then c else assoc_defined id ctxt
-
-let ref_value_cache ({i_cache = cache} as infos) ref =
- try
- Some (KeyTable.find cache.i_tab ref)
- with Not_found ->
- try
- let body =
- match ref with
- | RelKey n ->
- let len = Array.length cache.i_rels in
- let i = n - 1 in
- let () = if i < 0 || len <= i then raise Not_found in
- begin match Array.unsafe_get cache.i_rels i with
- | None -> raise Not_found
- | Some t -> lift n t
- end
- | VarKey id -> assoc_defined id (named_context cache.i_env)
- | ConstKey cst -> constant_value_in cache.i_env cst
- in
- let v = cache.i_repr infos body in
- KeyTable.add cache.i_tab ref v;
- Some v
- with
- | Not_found (* List.assoc *)
- | NotEvaluableConst _ (* Const *)
- -> None
-
-let evar_value cache ev =
- cache.i_sigma ev
-
-let defined_rels flags env =
-(* if red_local_const (snd flags) then*)
- let ctx = rel_context env in
- let len = List.length ctx in
- let ans = Array.make len None in
- let iter i (_, b, _) = match b with
- | None -> ()
- | Some _ -> Array.unsafe_set ans i b
- in
- let () = List.iteri iter ctx in
- ans
-(* else (0,[])*)
-
-let create mk_cl flgs env evars =
- let cache =
- { i_repr = mk_cl;
- i_env = env;
- i_sigma = evars;
- i_rels = defined_rels flgs env;
- i_tab = KeyTable.create 17 }
- in { i_flags = flgs; i_cache = cache }
-
-
-(**********************************************************************)
-(* Lazy reduction: the one used in kernel operations *)
-
-(* type of shared terms. fconstr and frterm are mutually recursive.
- * Clone of the constr structure, but completely mutable, and
- * annotated with reduction state (reducible or not).
- * - FLIFT is a delayed shift; allows sharing between 2 lifted copies
- * of a given term.
- * - FCLOS is a delayed substitution applied to a constr
- * - FLOCKED is used to erase the content of a reference that must
- * be updated. This is to allow the garbage collector to work
- * before the term is computed.
- *)
-
-(* Norm means the term is fully normalized and cannot create a redex
- when substituted
- Cstr means the term is in head normal form and that it can
- create a redex when substituted (i.e. constructor, fix, lambda)
- Whnf means we reached the head normal form and that it cannot
- create a redex when substituted
- Red is used for terms that might be reduced
-*)
-type red_state = Norm | Cstr | Whnf | Red
-
-let neutr = function
- | (Whnf|Norm) -> Whnf
- | (Red|Cstr) -> Red
-
-type fconstr = {
- mutable norm: red_state;
- mutable term: fterm }
-
-and fterm =
- | FRel of int
- | FAtom of constr (* Metas and Sorts *)
- | FCast of fconstr * cast_kind * fconstr
- | FFlex of table_key
- | FInd of pinductive
- | FConstruct of pconstructor
- | FApp of fconstr * fconstr array
- | FProj of projection * fconstr
- | FFix of fixpoint * fconstr subs
- | FCoFix of cofixpoint * fconstr subs
- | FCase of case_info * fconstr * fconstr * fconstr array
- | FCaseT of case_info * constr * fconstr * constr array * fconstr subs (* predicate and branches are closures *)
- | FLambda of int * (Name.t * constr) list * constr * fconstr subs
- | FProd of Name.t * fconstr * fconstr
- | FLetIn of Name.t * fconstr * fconstr * constr * fconstr subs
- | FEvar of existential * fconstr subs
- | FLIFT of int * fconstr
- | FCLOS of constr * fconstr subs
- | FLOCKED
-
-let fterm_of v = v.term
-let set_norm v = v.norm <- Norm
-let is_val v = match v.norm with Norm -> true | _ -> false
-
-let mk_atom c = {norm=Norm;term=FAtom c}
-
-(* Could issue a warning if no is still Red, pointing out that we loose
- sharing. *)
-let update v1 no t =
- if !share then
- (v1.norm <- no;
- v1.term <- t;
- v1)
- else {norm=no;term=t}
-
-(**********************************************************************)
-(* The type of (machine) stacks (= lambda-bar-calculus' contexts) *)
-
-type stack_member =
- | Zapp of fconstr array
- | Zcase of case_info * fconstr * fconstr array
- | ZcaseT of case_info * constr * constr array * fconstr subs
- | Zproj of int * int * constant
- | Zfix of fconstr * stack
- | Zshift of int
- | Zupdate of fconstr
-
-and stack = stack_member list
-
-let empty_stack = []
-let append_stack v s =
- if Int.equal (Array.length v) 0 then s else
- match s with
- | Zapp l :: s -> Zapp (Array.append v l) :: s
- | _ -> Zapp v :: s
-
-(* Collapse the shifts in the stack *)
-let zshift n s =
- match (n,s) with
- (0,_) -> s
- | (_,Zshift(k)::s) -> Zshift(n+k)::s
- | _ -> Zshift(n)::s
-
-let rec stack_args_size = function
- | Zapp v :: s -> Array.length v + stack_args_size s
- | Zshift(_)::s -> stack_args_size s
- | Zupdate(_)::s -> stack_args_size s
- | _ -> 0
-
-(* When used as an argument stack (only Zapp can appear) *)
-let rec decomp_stack = function
- | Zapp v :: s ->
- (match Array.length v with
- 0 -> decomp_stack s
- | 1 -> Some (v.(0), s)
- | _ ->
- Some (v.(0), (Zapp (Array.sub v 1 (Array.length v - 1)) :: s)))
- | _ -> None
-let array_of_stack s =
- let rec stackrec = function
- | [] -> []
- | Zapp args :: s -> args :: (stackrec s)
- | _ -> assert false
- in Array.concat (stackrec s)
-let rec stack_assign s p c = match s with
- | Zapp args :: s ->
- let q = Array.length args in
- if p >= q then
- Zapp args :: stack_assign s (p-q) c
- else
- (let nargs = Array.copy args in
- nargs.(p) <- c;
- Zapp nargs :: s)
- | _ -> s
-let rec stack_tail p s =
- if Int.equal p 0 then s else
- match s with
- | Zapp args :: s ->
- let q = Array.length args in
- if p >= q then stack_tail (p-q) s
- else Zapp (Array.sub args p (q-p)) :: s
- | _ -> failwith "stack_tail"
-let rec stack_nth s p = match s with
- | Zapp args :: s ->
- let q = Array.length args in
- if p >= q then stack_nth s (p-q)
- else args.(p)
- | _ -> raise Not_found
-
-(* Lifting. Preserves sharing (useful only for cell with norm=Red).
- lft_fconstr always create a new cell, while lift_fconstr avoids it
- when the lift is 0. *)
-let rec lft_fconstr n ft =
- match ft.term with
- | (FInd _|FConstruct _|FFlex(ConstKey _|VarKey _)) -> ft
- | FRel i -> {norm=Norm;term=FRel(i+n)}
- | FLambda(k,tys,f,e) -> {norm=Cstr; term=FLambda(k,tys,f,subs_shft(n,e))}
- | FFix(fx,e) -> {norm=Cstr; term=FFix(fx,subs_shft(n,e))}
- | FCoFix(cfx,e) -> {norm=Cstr; term=FCoFix(cfx,subs_shft(n,e))}
- | FLIFT(k,m) -> lft_fconstr (n+k) m
- | FLOCKED -> assert false
- | _ -> {norm=ft.norm; term=FLIFT(n,ft)}
-let lift_fconstr k f =
- if Int.equal k 0 then f else lft_fconstr k f
-let lift_fconstr_vect k v =
- if Int.equal k 0 then v else CArray.Fun1.map lft_fconstr k v
-
-let clos_rel e i =
- match expand_rel i e with
- | Inl(n,mt) -> lift_fconstr n mt
- | Inr(k,None) -> {norm=Norm; term= FRel k}
- | Inr(k,Some p) ->
- lift_fconstr (k-p) {norm=Red;term=FFlex(RelKey p)}
-
-(* since the head may be reducible, we might introduce lifts of 0 *)
-let compact_stack head stk =
- let rec strip_rec depth = function
- | Zshift(k)::s -> strip_rec (depth+k) s
- | Zupdate(m)::s ->
- (* Be sure to create a new cell otherwise sharing would be
- lost by the update operation *)
- let h' = lft_fconstr depth head in
- let _ = update m h'.norm h'.term in
- strip_rec depth s
- | stk -> zshift depth stk in
- strip_rec 0 stk
-
-(* Put an update mark in the stack, only if needed *)
-let zupdate m s =
- if !share && begin match m.norm with Red -> true | _ -> false end
- then
- let s' = compact_stack m s in
- let _ = m.term <- FLOCKED in
- Zupdate(m)::s'
- else s
-
-let mk_lambda env t =
- let (rvars,t') = decompose_lam t in
- FLambda(List.length rvars, List.rev rvars, t', env)
-
-let destFLambda clos_fun t =
- match t.term with
- FLambda(_,[(na,ty)],b,e) -> (na,clos_fun e ty,clos_fun (subs_lift e) b)
- | FLambda(n,(na,ty)::tys,b,e) ->
- (na,clos_fun e ty,{norm=Cstr;term=FLambda(n-1,tys,b,subs_lift e)})
- | _ -> assert false
- (* t must be a FLambda and binding list cannot be empty *)
-
-(* Optimization: do not enclose variables in a closure.
- Makes variable access much faster *)
-let mk_clos e t =
- match kind_of_term t with
- | Rel i -> clos_rel e i
- | Var x -> { norm = Red; term = FFlex (VarKey x) }
- | Const c -> { norm = Red; term = FFlex (ConstKey c) }
- | Meta _ | Sort _ -> { norm = Norm; term = FAtom t }
- | Ind kn -> { norm = Norm; term = FInd kn }
- | Construct kn -> { norm = Cstr; term = FConstruct kn }
- | (CoFix _|Lambda _|Fix _|Prod _|Evar _|App _|Case _|Cast _|LetIn _|Proj _) ->
- {norm = Red; term = FCLOS(t,e)}
-
-let mk_clos_vect env v = CArray.Fun1.map mk_clos env v
-
-(* Translate the head constructor of t from constr to fconstr. This
- function is parameterized by the function to apply on the direct
- subterms.
- Could be used insted of mk_clos. *)
-let mk_clos_deep clos_fun env t =
- match kind_of_term t with
- | (Rel _|Ind _|Const _|Construct _|Var _|Meta _ | Sort _) ->
- mk_clos env t
- | Cast (a,k,b) ->
- { norm = Red;
- term = FCast (clos_fun env a, k, clos_fun env b)}
- | App (f,v) ->
- { norm = Red;
- term = FApp (clos_fun env f, CArray.Fun1.map clos_fun env v) }
- | Proj (p,c) ->
- { norm = Red;
- term = FProj (p, clos_fun env c) }
- | Case (ci,p,c,v) ->
- { norm = Red;
- term = FCaseT (ci, p, clos_fun env c, v, env) }
- | Fix fx ->
- { norm = Cstr; term = FFix (fx, env) }
- | CoFix cfx ->
- { norm = Cstr; term = FCoFix(cfx,env) }
- | Lambda _ ->
- { norm = Cstr; term = mk_lambda env t }
- | Prod (n,t,c) ->
- { norm = Whnf;
- term = FProd (n, clos_fun env t, clos_fun (subs_lift env) c) }
- | LetIn (n,b,t,c) ->
- { norm = Red;
- term = FLetIn (n, clos_fun env b, clos_fun env t, c, env) }
- | Evar ev ->
- { norm = Red; term = FEvar(ev,env) }
-
-(* A better mk_clos? *)
-let mk_clos2 = mk_clos_deep mk_clos
-
-(* The inverse of mk_clos_deep: move back to constr *)
-let rec to_constr constr_fun lfts v =
- match v.term with
- | FRel i -> mkRel (reloc_rel i lfts)
- | FFlex (RelKey p) -> mkRel (reloc_rel p lfts)
- | FFlex (VarKey x) -> mkVar x
- | FAtom c -> exliftn lfts c
- | FCast (a,k,b) ->
- mkCast (constr_fun lfts a, k, constr_fun lfts b)
- | FFlex (ConstKey op) -> mkConstU op
- | FInd op -> mkIndU op
- | FConstruct op -> mkConstructU op
- | FCase (ci,p,c,ve) ->
- mkCase (ci, constr_fun lfts p,
- constr_fun lfts c,
- CArray.Fun1.map constr_fun lfts ve)
- | FCaseT (ci,p,c,ve,env) ->
- mkCase (ci, constr_fun lfts (mk_clos env p),
- constr_fun lfts c,
- Array.map (fun b -> constr_fun lfts (mk_clos env b)) ve)
- | FFix ((op,(lna,tys,bds)),e) ->
- let n = Array.length bds in
- let ftys = CArray.Fun1.map mk_clos e tys in
- let fbds = CArray.Fun1.map mk_clos (subs_liftn n e) bds in
- let lfts' = el_liftn n lfts in
- mkFix (op, (lna, CArray.Fun1.map constr_fun lfts ftys,
- CArray.Fun1.map constr_fun lfts' fbds))
- | FCoFix ((op,(lna,tys,bds)),e) ->
- let n = Array.length bds in
- let ftys = CArray.Fun1.map mk_clos e tys in
- let fbds = CArray.Fun1.map mk_clos (subs_liftn n e) bds in
- let lfts' = el_liftn (Array.length bds) lfts in
- mkCoFix (op, (lna, CArray.Fun1.map constr_fun lfts ftys,
- CArray.Fun1.map constr_fun lfts' fbds))
- | FApp (f,ve) ->
- mkApp (constr_fun lfts f,
- CArray.Fun1.map constr_fun lfts ve)
- | FProj (p,c) ->
- mkProj (p,constr_fun lfts c)
-
- | FLambda _ ->
- let (na,ty,bd) = destFLambda mk_clos2 v in
- mkLambda (na, constr_fun lfts ty,
- constr_fun (el_lift lfts) bd)
- | FProd (n,t,c) ->
- mkProd (n, constr_fun lfts t,
- constr_fun (el_lift lfts) c)
- | FLetIn (n,b,t,f,e) ->
- let fc = mk_clos2 (subs_lift e) f in
- mkLetIn (n, constr_fun lfts b,
- constr_fun lfts t,
- constr_fun (el_lift lfts) fc)
- | FEvar ((ev,args),env) ->
- mkEvar(ev,Array.map (fun a -> constr_fun lfts (mk_clos2 env a)) args)
- | FLIFT (k,a) -> to_constr constr_fun (el_shft k lfts) a
- | FCLOS (t,env) ->
- let fr = mk_clos2 env t in
- let unfv = update v fr.norm fr.term in
- to_constr constr_fun lfts unfv
- | FLOCKED -> assert false (*mkVar(Id.of_string"_LOCK_")*)
-
-(* This function defines the correspondance between constr and
- fconstr. When we find a closure whose substitution is the identity,
- then we directly return the constr to avoid possibly huge
- reallocation. *)
-let term_of_fconstr =
- let rec term_of_fconstr_lift lfts v =
- match v.term with
- | FCLOS(t,env) when is_subs_id env && is_lift_id lfts -> t
- | FLambda(_,tys,f,e) when is_subs_id e && is_lift_id lfts ->
- compose_lam (List.rev tys) f
- | FFix(fx,e) when is_subs_id e && is_lift_id lfts -> mkFix fx
- | FCoFix(cfx,e) when is_subs_id e && is_lift_id lfts -> mkCoFix cfx
- | _ -> to_constr term_of_fconstr_lift lfts v in
- term_of_fconstr_lift el_id
-
-
-
-(* fstrong applies unfreeze_fun recursively on the (freeze) term and
- * yields a term. Assumes that the unfreeze_fun never returns a
- * FCLOS term.
-let rec fstrong unfreeze_fun lfts v =
- to_constr (fstrong unfreeze_fun) lfts (unfreeze_fun v)
-*)
-
-let rec zip m stk =
- match stk with
- | [] -> m
- | Zapp args :: s -> zip {norm=neutr m.norm; term=FApp(m, args)} s
- | Zcase(ci,p,br)::s ->
- let t = FCase(ci, p, m, br) in
- zip {norm=neutr m.norm; term=t} s
- | ZcaseT(ci,p,br,e)::s ->
- let t = FCaseT(ci, p, m, br, e) in
- zip {norm=neutr m.norm; term=t} s
- | Zproj (i,j,cst) :: s ->
- zip {norm=neutr m.norm; term=FProj(Projection.make cst true,m)} s
- | Zfix(fx,par)::s ->
- zip fx (par @ append_stack [|m|] s)
- | Zshift(n)::s ->
- zip (lift_fconstr n m) s
- | Zupdate(rf)::s ->
- zip (update rf m.norm m.term) s
-
-let fapp_stack (m,stk) = zip m stk
-
-(*********************************************************************)
-
-(* The assertions in the functions below are granted because they are
- called only when m is a constructor, a cofix
- (strip_update_shift_app), a fix (get_nth_arg) or an abstraction
- (strip_update_shift, through get_arg). *)
-
-(* optimised for the case where there are no shifts... *)
-let strip_update_shift_app_red head stk =
- let rec strip_rec rstk h depth = function
- | Zshift(k) as e :: s ->
- strip_rec (e::rstk) (lift_fconstr k h) (depth+k) s
- | (Zapp args :: s) ->
- strip_rec (Zapp args :: rstk)
- {norm=h.norm;term=FApp(h,args)} depth s
- | Zupdate(m)::s ->
- strip_rec rstk (update m h.norm h.term) depth s
- | stk -> (depth,List.rev rstk, stk) in
- strip_rec [] head 0 stk
-
-let strip_update_shift_app head stack =
- assert (match head.norm with Red -> false | _ -> true);
- strip_update_shift_app_red head stack
-
-let get_nth_arg head n stk =
- assert (match head.norm with Red -> false | _ -> true);
- let rec strip_rec rstk h n = function
- | Zshift(k) as e :: s ->
- strip_rec (e::rstk) (lift_fconstr k h) n s
- | Zapp args::s' ->
- let q = Array.length args in
- if n >= q
- then
- strip_rec (Zapp args::rstk) {norm=h.norm;term=FApp(h,args)} (n-q) s'
- else
- let bef = Array.sub args 0 n in
- let aft = Array.sub args (n+1) (q-n-1) in
- let stk' =
- List.rev (if Int.equal n 0 then rstk else (Zapp bef :: rstk)) in
- (Some (stk', args.(n)), append_stack aft s')
- | Zupdate(m)::s ->
- strip_rec rstk (update m h.norm h.term) n s
- | s -> (None, List.rev rstk @ s) in
- strip_rec [] head n stk
-
-(* Beta reduction: look for an applied argument in the stack.
- Since the encountered update marks are removed, h must be a whnf *)
-let rec get_args n tys f e stk =
- match stk with
- Zupdate r :: s ->
- let _hd = update r Cstr (FLambda(n,tys,f,e)) in
- get_args n tys f e s
- | Zshift k :: s ->
- get_args n tys f (subs_shft (k,e)) s
- | Zapp l :: s ->
- let na = Array.length l in
- if n == na then (Inl (subs_cons(l,e)),s)
- else if n < na then (* more arguments *)
- let args = Array.sub l 0 n in
- let eargs = Array.sub l n (na-n) in
- (Inl (subs_cons(args,e)), Zapp eargs :: s)
- else (* more lambdas *)
- let etys = List.skipn na tys in
- get_args (n-na) etys f (subs_cons(l,e)) s
- | _ -> (Inr {norm=Cstr;term=FLambda(n,tys,f,e)}, stk)
-
-(* Eta expansion: add a reference to implicit surrounding lambda at end of stack *)
-let rec eta_expand_stack = function
- | (Zapp _ | Zfix _ | Zcase _ | ZcaseT _ | Zproj _
- | Zshift _ | Zupdate _ as e) :: s ->
- e :: eta_expand_stack s
- | [] ->
- [Zshift 1; Zapp [|{norm=Norm; term= FRel 1}|]]
-
-(* Iota reduction: extract the arguments to be passed to the Case
- branches *)
-let rec reloc_rargs_rec depth stk =
- match stk with
- Zapp args :: s ->
- Zapp (lift_fconstr_vect depth args) :: reloc_rargs_rec depth s
- | Zshift(k)::s -> if Int.equal k depth then s else reloc_rargs_rec (depth-k) s
- | _ -> stk
-
-let reloc_rargs depth stk =
- if Int.equal depth 0 then stk else reloc_rargs_rec depth stk
-
-let rec try_drop_parameters depth n argstk =
- match argstk with
- Zapp args::s ->
- let q = Array.length args in
- if n > q then try_drop_parameters depth (n-q) s
- else if Int.equal n q then reloc_rargs depth s
- else
- let aft = Array.sub args n (q-n) in
- reloc_rargs depth (append_stack aft s)
- | Zshift(k)::s -> try_drop_parameters (depth-k) n s
- | [] ->
- if Int.equal n 0 then []
- else raise Not_found
- | _ -> assert false
- (* strip_update_shift_app only produces Zapp and Zshift items *)
-
-let drop_parameters depth n argstk =
- try try_drop_parameters depth n argstk
- with Not_found ->
- (* we know that n < stack_args_size(argstk) (if well-typed term) *)
- anomaly (Pp.str "ill-typed term: found a match on a partially applied constructor")
-
-(** [eta_expand_ind_stack env ind c s t] computes stacks corresponding
- to the conversion of the eta expansion of t, considered as an inhabitant
- of ind, and the Constructor c of this inductive type applied to arguments
- s.
- @assumes [t] is an irreducible term, and not a constructor. [ind] is the inductive
- of the constructor term [c]
- @raises Not_found if the inductive is not a primitive record, or if the
- constructor is partially applied.
- *)
-let eta_expand_ind_stack env ind m s (f, s') =
- let mib = lookup_mind (fst ind) env in
- match mib.Declarations.mind_record with
- | Some (Some (_,projs,pbs)) when
- mib.Declarations.mind_finite <> Decl_kinds.CoFinite ->
- (* (Construct, pars1 .. parsm :: arg1...argn :: []) ~= (f, s') ->
- arg1..argn ~= (proj1 t...projn t) where t = zip (f,s') *)
- let pars = mib.Declarations.mind_nparams in
- let right = fapp_stack (f, s') in
- let (depth, args, s) = strip_update_shift_app m s in
- (** Try to drop the params, might fail on partially applied constructors. *)
- let argss = try_drop_parameters depth pars args in
- let hstack = Array.map (fun p -> { norm = Red; (* right can't be a constructor though *)
- term = FProj (Projection.make p true, right) }) projs in
- argss, [Zapp hstack]
- | _ -> raise Not_found (* disallow eta-exp for non-primitive records *)
-
-let rec project_nth_arg n argstk =
- match argstk with
- | Zapp args :: s ->
- let q = Array.length args in
- if n >= q then project_nth_arg (n - q) s
- else (* n < q *) args.(n)
- | _ -> assert false
- (* After drop_parameters we have a purely applicative stack *)
-
-
-(* Iota reduction: expansion of a fixpoint.
- * Given a fixpoint and a substitution, returns the corresponding
- * fixpoint body, and the substitution in which it should be
- * evaluated: its first variables are the fixpoint bodies
- *
- * FCLOS(fix Fi {F0 := T0 .. Fn-1 := Tn-1}, S)
- * -> (S. FCLOS(F0,S) . ... . FCLOS(Fn-1,S), Ti)
- *)
-(* does not deal with FLIFT *)
-let contract_fix_vect fix =
- let (thisbody, make_body, env, nfix) =
- match fix with
- | FFix (((reci,i),(_,_,bds as rdcl)),env) ->
- (bds.(i),
- (fun j -> { norm = Cstr; term = FFix (((reci,j),rdcl),env) }),
- env, Array.length bds)
- | FCoFix ((i,(_,_,bds as rdcl)),env) ->
- (bds.(i),
- (fun j -> { norm = Cstr; term = FCoFix ((j,rdcl),env) }),
- env, Array.length bds)
- | _ -> assert false
- in
- (subs_cons(Array.init nfix make_body, env), thisbody)
-
-(*********************************************************************)
-(* A machine that inspects the head of a term until it finds an
- atom or a subterm that may produce a redex (abstraction,
- constructor, cofix, letin, constant), or a neutral term (product,
- inductive) *)
-let rec knh info m stk =
- match m.term with
- | FLIFT(k,a) -> knh info a (zshift k stk)
- | FCLOS(t,e) -> knht info e t (zupdate m stk)
- | FLOCKED -> assert false
- | FApp(a,b) -> knh info a (append_stack b (zupdate m stk))
- | FCase(ci,p,t,br) -> knh info t (Zcase(ci,p,br)::zupdate m stk)
- | FCaseT(ci,p,t,br,e) -> knh info t (ZcaseT(ci,p,br,e)::zupdate m stk)
- | FFix(((ri,n),(_,_,_)),_) ->
- (match get_nth_arg m ri.(n) stk with
- (Some(pars,arg),stk') -> knh info arg (Zfix(m,pars)::stk')
- | (None, stk') -> (m,stk'))
- | FCast(t,_,_) -> knh info t stk
- | FProj (p,c) ->
- let unf = Projection.unfolded p in
- if unf || red_set info.i_flags (fCONST (Projection.constant p)) then
- (match try Some (lookup_projection p (info_env info)) with Not_found -> None with
- | None -> (m, stk)
- | Some pb ->
- knh info c (Zproj (pb.Declarations.proj_npars, pb.Declarations.proj_arg,
- Projection.constant p)
- :: zupdate m stk))
- else (m,stk)
-
-(* cases where knh stops *)
- | (FFlex _|FLetIn _|FConstruct _|FEvar _|
- FCoFix _|FLambda _|FRel _|FAtom _|FInd _|FProd _) ->
- (m, stk)
-
-(* The same for pure terms *)
-and knht info e t stk =
- match kind_of_term t with
- | App(a,b) ->
- knht info e a (append_stack (mk_clos_vect e b) stk)
- | Case(ci,p,t,br) ->
- knht info e t (ZcaseT(ci, p, br, e)::stk)
- | Fix _ -> knh info (mk_clos2 e t) stk
- | Cast(a,_,_) -> knht info e a stk
- | Rel n -> knh info (clos_rel e n) stk
- | Proj (p,c) -> knh info (mk_clos2 e t) stk
- | (Lambda _|Prod _|Construct _|CoFix _|Ind _|
- LetIn _|Const _|Var _|Evar _|Meta _|Sort _) ->
- (mk_clos2 e t, stk)
-
-
-(************************************************************************)
-
-(* Computes a weak head normal form from the result of knh. *)
-let rec knr info m stk =
- match m.term with
- | FLambda(n,tys,f,e) when red_set info.i_flags fBETA ->
- (match get_args n tys f e stk with
- Inl e', s -> knit info e' f s
- | Inr lam, s -> (lam,s))
- | FFlex(ConstKey (kn,_ as c)) when red_set info.i_flags (fCONST kn) ->
- (match ref_value_cache info (ConstKey c) with
- Some v -> kni info v stk
- | None -> (set_norm m; (m,stk)))
- | FFlex(VarKey id) when red_set info.i_flags (fVAR id) ->
- (match ref_value_cache info (VarKey id) with
- Some v -> kni info v stk
- | None -> (set_norm m; (m,stk)))
- | FFlex(RelKey k) when red_set info.i_flags fDELTA ->
- (match ref_value_cache info (RelKey k) with
- Some v -> kni info v stk
- | None -> (set_norm m; (m,stk)))
- | FConstruct((ind,c),u) when red_set info.i_flags fIOTA ->
- (match strip_update_shift_app m stk with
- (depth, args, Zcase(ci,_,br)::s) ->
- assert (ci.ci_npar>=0);
- let rargs = drop_parameters depth ci.ci_npar args in
- kni info br.(c-1) (rargs@s)
- | (depth, args, ZcaseT(ci,_,br,e)::s) ->
- assert (ci.ci_npar>=0);
- let rargs = drop_parameters depth ci.ci_npar args in
- knit info e br.(c-1) (rargs@s)
- | (_, cargs, Zfix(fx,par)::s) ->
- let rarg = fapp_stack(m,cargs) in
- let stk' = par @ append_stack [|rarg|] s in
- let (fxe,fxbd) = contract_fix_vect fx.term in
- knit info fxe fxbd stk'
- | (depth, args, Zproj (n, m, cst)::s) ->
- let rargs = drop_parameters depth n args in
- let rarg = project_nth_arg m rargs in
- kni info rarg s
- | (_,args,s) -> (m,args@s))
- | FCoFix _ when red_set info.i_flags fIOTA ->
- (match strip_update_shift_app m stk with
- (_, args, (((Zcase _|ZcaseT _|Zproj _)::_) as stk')) ->
- let (fxe,fxbd) = contract_fix_vect m.term in
- knit info fxe fxbd (args@stk')
- | (_,args,s) -> (m,args@s))
- | FLetIn (_,v,_,bd,e) when red_set info.i_flags fZETA ->
- knit info (subs_cons([|v|],e)) bd stk
- | FEvar(ev,env) ->
- (match evar_value info.i_cache ev with
- Some c -> knit info env c stk
- | None -> (m,stk))
- | _ -> (m,stk)
-
-(* Computes the weak head normal form of a term *)
-and kni info m stk =
- let (hm,s) = knh info m stk in
- knr info hm s
-and knit info e t stk =
- let (ht,s) = knht info e t stk in
- knr info ht s
-
-let kh info v stk = fapp_stack(kni info v stk)
-
-(************************************************************************)
-
-let rec zip_term zfun m stk =
- match stk with
- | [] -> m
- | Zapp args :: s ->
- zip_term zfun (mkApp(m, Array.map zfun args)) s
- | Zcase(ci,p,br)::s ->
- let t = mkCase(ci, zfun p, m, Array.map zfun br) in
- zip_term zfun t s
- | ZcaseT(ci,p,br,e)::s ->
- let t = mkCase(ci, zfun (mk_clos e p), m,
- Array.map (fun b -> zfun (mk_clos e b)) br) in
- zip_term zfun t s
- | Zproj(_,_,p)::s ->
- let t = mkProj (Projection.make p true, m) in
- zip_term zfun t s
- | Zfix(fx,par)::s ->
- let h = mkApp(zip_term zfun (zfun fx) par,[|m|]) in
- zip_term zfun h s
- | Zshift(n)::s ->
- zip_term zfun (lift n m) s
- | Zupdate(rf)::s ->
- zip_term zfun m s
-
-(* Computes the strong normal form of a term.
- 1- Calls kni
- 2- tries to rebuild the term. If a closure still has to be computed,
- calls itself recursively. *)
-let rec kl info m =
- if is_val m then (incr prune; term_of_fconstr m)
- else
- let (nm,s) = kni info m [] in
- let _ = fapp_stack(nm,s) in (* to unlock Zupdates! *)
- zip_term (kl info) (norm_head info nm) s
-
-(* no redex: go up for atoms and already normalized terms, go down
- otherwise. *)
-and norm_head info m =
- if is_val m then (incr prune; term_of_fconstr m) else
- match m.term with
- | FLambda(n,tys,f,e) ->
- let (e',rvtys) =
- List.fold_left (fun (e,ctxt) (na,ty) ->
- (subs_lift e, (na,kl info (mk_clos e ty))::ctxt))
- (e,[]) tys in
- let bd = kl info (mk_clos e' f) in
- List.fold_left (fun b (na,ty) -> mkLambda(na,ty,b)) bd rvtys
- | FLetIn(na,a,b,f,e) ->
- let c = mk_clos (subs_lift e) f in
- mkLetIn(na, kl info a, kl info b, kl info c)
- | FProd(na,dom,rng) ->
- mkProd(na, kl info dom, kl info rng)
- | FCoFix((n,(na,tys,bds)),e) ->
- let ftys = CArray.Fun1.map mk_clos e tys in
- let fbds =
- CArray.Fun1.map mk_clos (subs_liftn (Array.length na) e) bds in
- mkCoFix(n,(na, CArray.Fun1.map kl info ftys, CArray.Fun1.map kl info fbds))
- | FFix((n,(na,tys,bds)),e) ->
- let ftys = CArray.Fun1.map mk_clos e tys in
- let fbds =
- CArray.Fun1.map mk_clos (subs_liftn (Array.length na) e) bds in
- mkFix(n,(na, CArray.Fun1.map kl info ftys, CArray.Fun1.map kl info fbds))
- | FEvar((i,args),env) ->
- mkEvar(i, Array.map (fun a -> kl info (mk_clos env a)) args)
- | FProj (p,c) ->
- mkProj (p, kl info c)
- | t -> term_of_fconstr m
-
-(* Initialization and then normalization *)
-
-(* weak reduction *)
-let whd_val info v =
- with_stats (lazy (term_of_fconstr (kh info v [])))
-
-(* strong reduction *)
-let norm_val info v =
- with_stats (lazy (kl info v))
-
-let inject c = mk_clos (subs_id 0) c
-
-let whd_stack infos m stk =
- let k = kni infos m stk in
- let _ = fapp_stack k in (* to unlock Zupdates! *)
- k
-
-(* cache of constants: the body is computed only when needed. *)
-type clos_infos = fconstr infos
-
-let create_clos_infos ?(evars=fun _ -> None) flgs env =
- create (fun _ -> inject) flgs env evars
-let oracle_of_infos infos = Environ.oracle infos.i_cache.i_env
-
-let env_of_infos infos = infos.i_cache.i_env
-
-let infos_with_reds infos reds =
- { infos with i_flags = reds }
-
-let unfold_reference info key =
- match key with
- | ConstKey (kn,_) ->
- if red_set info.i_flags (fCONST kn) then
- ref_value_cache info key
- else None
- | VarKey i ->
- if red_set info.i_flags (fVAR i) then
- ref_value_cache info key
- else None
- | _ -> ref_value_cache info key
-