]> matita.cs.unibo.it Git - helm.git/blobdiff - helm/ocaml/cic_proof_checking/cicReductionMachine.ml
* if no configuration file is found, issue a warning but doesn't crash
[helm.git] / helm / ocaml / cic_proof_checking / cicReductionMachine.ml
index 55db97045845401538bd4a4557963c17ad32b858..30b688264776e8f2c77816fdf52e5ece0577daa5 100644 (file)
@@ -45,422 +45,689 @@ let debug t env s =
    end
 ;;
 
-type env = Cic.term list;;
-type stack = Cic.term list;;
-type config =
- int * env * Cic.term Cic.explicit_named_substitution * Cic.term * stack;;
+module type Strategy =
+ sig
+  type stack_term
+  type env_term
+  type ens_term
+  val to_stack : Cic.term -> stack_term
+  val to_stack_list : Cic.term list -> stack_term list
+  val to_env : Cic.term -> env_term
+  val to_ens : Cic.term -> ens_term
+  val from_stack :
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term -> Cic.term
+  val from_stack_list :
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term list -> Cic.term list
+  val from_env : env_term -> Cic.term
+  val from_ens : ens_term -> Cic.term
+  val stack_to_env :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution *
+      Cic.term * stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   stack_term -> env_term
+  val compute_to_env :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term *
+      stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+    Cic.term -> env_term
+  val compute_to_stack :
+   reduce:
+    (int * env_term list * ens_term Cic.explicit_named_substitution * Cic.term *
+      stack_term list -> Cic.term) ->
+   unwind:
+    (int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+      Cic.term -> Cic.term) ->
+   int -> env_term list -> ens_term Cic.explicit_named_substitution ->
+    Cic.term -> stack_term
+ end
+;;
 
-let call_by_name = false;;   (* false means call_by_value *)
+module CallByNameStrategy =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = unwind k e ens t
+  let compute_to_env ~reduce ~unwind k e ens t = unwind k e ens t
+ end
+;;
 
-(* k is the length of the environment e *)
-(* m is the current depth inside the term *)
-let unwind' m k e ens t = 
- let module C = Cic in
- let module S = CicSubstitution in
-  if k = 0 && ens = [] then
-   t
-  else 
-   let rec unwind_aux m =
-    function
-       C.Rel n as t ->
-        if n <= m then t else
-         let d =
-          try
-           Some (List.nth e (n-m-1))
-          with _ -> None
-         in
-          (match d with 
-              Some t' ->
-               if m = 0 then t' else S.lift m t'
-            | None -> C.Rel (n-k)
-          )
-     | C.Var (uri,exp_named_subst) ->
+module CallByValueStrategy =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t = reduce (k,e,ens,t,[])
+ end
+;;
+
+module CallByValueStrategyByNameOnConstants =
+ struct
+  type stack_term = Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = v
+  let to_stack_list l = l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind v = v
+  let from_stack_list ~unwind l = l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens =
+   function
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens =
+   function
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+ end
+;;
+
+module LazyCallByValueStrategy =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+  let compute_to_env ~reduce ~unwind k e ens t = lazy (reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByValueStrategyByNameOnConstants =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t =
+   lazy (
+    match t with
+       Cic.Const _ as t -> unwind k e ens t    
+     | t -> reduce (k,e,ens,t,[]))
+  let compute_to_env ~reduce ~unwind k e ens t =
+   lazy (
+    match t with
+       Cic.Const _ as t -> unwind k e ens t    
+     | t -> reduce (k,e,ens,t,[]))
+ end
+;;
+
+module LazyCallByNameStrategy =
+ struct
+  type stack_term = Cic.term lazy_t
+  type env_term = Cic.term lazy_t
+  type ens_term = Cic.term lazy_t
+  let to_stack v = lazy v
+  let to_stack_list l = List.map to_stack l
+  let to_env v = lazy v
+  let to_ens v = lazy v
+  let from_stack ~unwind v = Lazy.force v
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = Lazy.force v
+  let from_ens v = Lazy.force v
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+  let compute_to_env ~reduce ~unwind k e ens t = lazy (unwind k e ens t)
+ end
+;;
+
+module
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns
+=
+ struct
+  type stack_term = reduce:bool -> Cic.term
+  type env_term = reduce:bool -> Cic.term
+  type ens_term = reduce:bool -> Cic.term
+  let to_stack v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let to_stack_list l = List.map to_stack l
+  let to_env v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let to_ens v =
+   let value = lazy v in
+    fun ~reduce -> Lazy.force value
+  let from_stack ~unwind v = (v ~reduce:false)
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = (v ~reduce:true)
+  let from_ens v = (v ~reduce:true)
+  let stack_to_env ~reduce ~unwind v = v
+  let compute_to_stack ~reduce ~unwind k e ens t =
+   let svalue =
+     lazy (
+      match t with
+         Cic.Const _ as t -> unwind k e ens t    
+       | t -> reduce (k,e,ens,t,[])
+     ) in
+   let lvalue =
+    lazy (unwind k e ens t)
+   in
+    fun ~reduce ->
+     if reduce then Lazy.force svalue else Lazy.force lvalue
+  let compute_to_env ~reduce ~unwind k e ens t =
+   let svalue =
+     lazy (
+      match t with
+         Cic.Const _ as t -> unwind k e ens t    
+       | t -> reduce (k,e,ens,t,[])
+     ) in
+   let lvalue =
+    lazy (unwind k e ens t)
+   in
+    fun ~reduce ->
+     if reduce then Lazy.force svalue else Lazy.force lvalue
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsStrategy =
+ struct
+  type stack_term =
+   int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = (0,[],[],v)
+  let to_stack_list l = List.map to_stack l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind (k,e,ens,t) = reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t =
+   unwind k e ens t
+  let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
+ end
+;;
+
+module ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy =
+ struct
+  type stack_term =
+   int * Cic.term list * Cic.term Cic.explicit_named_substitution * Cic.term
+  type env_term = Cic.term
+  type ens_term = Cic.term
+  let to_stack v = (0,[],[],v)
+  let to_stack_list l = List.map to_stack l
+  let to_env v = v
+  let to_ens v = v
+  let from_stack ~unwind (k,e,ens,t) = unwind k e ens t
+  let from_stack_list ~unwind l = List.map (from_stack ~unwind) l
+  let from_env v = v
+  let from_ens v = v
+  let stack_to_env ~reduce ~unwind (k,e,ens,t) =
+   match t with
+      Cic.Const _ as t -> unwind k e ens t    
+    | t -> reduce (k,e,ens,t,[])
+  let compute_to_env ~reduce ~unwind k e ens t =
+   unwind k e ens t
+  let compute_to_stack ~reduce ~unwind k e ens t = (k,e,ens,t)
+ end
+;;
+
+module Reduction(RS : Strategy) =
+ struct
+  type env = RS.env_term list
+  type ens = RS.ens_term Cic.explicit_named_substitution
+  type stack = RS.stack_term list
+  type config = int * env * ens * Cic.term * stack
+
+  (* k is the length of the environment e *)
+  (* m is the current depth inside the term *)
+  let unwind' m k e ens t = 
+   let module C = Cic in
+   let module S = CicSubstitution in
+    if k = 0 && ens = [] then
+     t
+    else 
+     let rec unwind_aux m =
+      function
+         C.Rel n as t ->
+          if n <= m then t else
+           let d =
+            try
+             Some (RS.from_env (List.nth e (n-m-1)))
+            with _ -> None
+           in
+            (match d with 
+                Some t' ->
+                 if m = 0 then t' else S.lift m t'
+              | None -> C.Rel (n-k)
+            )
+       | C.Var (uri,exp_named_subst) ->
 (*
 prerr_endline ("%%%%%UWVAR " ^ String.concat " ; " (List.map (function (uri,t) -> UriManager.string_of_uri uri ^ " := " ^ CicPp.ppterm t) ens)) ;
 *)
-       if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
-        CicSubstitution.lift m (List.assq uri ens)
-       else
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable (_,_,_,params) -> params
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.Var (uri,exp_named_subst')
-     | C.Meta (i,l) ->
-        let l' =
-         List.map
-          (function
-              None -> None
-            | Some t -> Some (unwind_aux m t)
-          ) l
-        in
-         C.Meta (i, l')
-     | C.Sort _ as t -> t
-     | C.Implicit as t -> t
-     | C.Cast (te,ty) -> C.Cast (unwind_aux m te, unwind_aux m ty) (*CSC ??? *)
-     | C.Prod (n,s,t) -> C.Prod (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.Lambda (n,s,t) -> C.Lambda (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.LetIn (n,s,t) -> C.LetIn (n, unwind_aux m s, unwind_aux (m + 1) t)
-     | C.Appl l -> C.Appl (List.map (unwind_aux m) l)
-     | C.Const (uri,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant (_,_,_,params) -> params
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof (_,_,_,_,params) -> params
-           | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.Const (uri,exp_named_subst')
-     | C.MutInd (uri,i,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition (_,params,_) -> params
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.MutInd (uri,i,exp_named_subst')
-     | C.MutConstruct (uri,i,j,exp_named_subst) ->
-        let params =
-         (match CicEnvironment.get_obj uri with
-             C.Constant _ -> raise ReferenceToConstant
-           | C.Variable _ -> raise ReferenceToVariable
-           | C.CurrentProof _ -> raise ReferenceToCurrentProof
-           | C.InductiveDefinition (_,params,_) -> params
-         )
-        in
-         let exp_named_subst' =
-          substaux_in_exp_named_subst params exp_named_subst m 
-         in
-          C.MutConstruct (uri,i,j,exp_named_subst')
-     | C.MutCase (sp,i,outt,t,pl) ->
-        C.MutCase (sp,i,unwind_aux m outt, unwind_aux m t,
-         List.map (unwind_aux m) pl)
-     | C.Fix (i,fl) ->
-        let len = List.length fl in
-        let substitutedfl =
-         List.map
-          (fun (name,i,ty,bo) ->
-            (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
-           fl
-        in
-         C.Fix (i, substitutedfl)
-     | C.CoFix (i,fl) ->
-        let len = List.length fl in
-        let substitutedfl =
-         List.map
-          (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
-           fl
-        in
-         C.CoFix (i, substitutedfl)
-   and substaux_in_exp_named_subst params exp_named_subst' m  =
-(*CSC: Idea di Andrea di ordinare compatibilmente con l'ordine dei params
-    let ens' =
-     List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
-(*CSC: qui liftiamo tutti gli ens anche se magari me ne servono la meta'!!! *)
-      List.map (function (uri,t) -> uri, CicSubstitution.lift m t) ens
-    in
-    let rec filter_and_lift =
-     function
-        [] -> []
-      | uri::tl ->
-         let r = filter_and_lift tl in
-          (try
-            (uri,(List.assq uri ens'))::r
-           with
-            Not_found -> r
-          )
-    in
-     filter_and_lift params
-*)
-
-(*CSC: invece di concatenare sarebbe meglio rispettare l'ordine dei params *)
-(*CSC: e' vero???? una veloce prova non sembra confermare la teoria        *)
-
-(*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
-(*CSC: codice altamente inefficiente *)
-    let rec filter_and_lift already_instantiated =
-     function
-        [] -> []
-      | (uri,t)::tl when
-          List.for_all
-           (function (uri',_) -> not (UriManager.eq uri uri')) exp_named_subst'
-          &&
-           not (List.mem uri already_instantiated)
-          &&
-           List.mem uri params
-         ->
-          (uri,CicSubstitution.lift m t) ::
-           (filter_and_lift (uri::already_instantiated) tl)
-      | _::tl -> filter_and_lift already_instantiated tl
+         if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
+          CicSubstitution.lift m (RS.from_ens (List.assq uri ens))
+         else
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable (_,_,_,params) -> params
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.Var (uri,exp_named_subst')
+       | C.Meta (i,l) ->
+          let l' =
+           List.map
+            (function
+                None -> None
+              | Some t -> Some (unwind_aux m t)
+            ) l
+          in
+           C.Meta (i, l')
+       | C.Sort _ as t -> t
+       | C.Implicit as t -> t
+       | C.Cast (te,ty) -> C.Cast (unwind_aux m te, unwind_aux m ty) (*CSC ???*)
+       | C.Prod (n,s,t) -> C.Prod (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.Lambda (n,s,t) -> C.Lambda (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.LetIn (n,s,t) -> C.LetIn (n, unwind_aux m s, unwind_aux (m + 1) t)
+       | C.Appl l -> C.Appl (List.map (unwind_aux m) l)
+       | C.Const (uri,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant (_,_,_,params) -> params
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof (_,_,_,_,params) -> params
+             | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.Const (uri,exp_named_subst')
+       | C.MutInd (uri,i,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition (_,params,_) -> params
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.MutInd (uri,i,exp_named_subst')
+       | C.MutConstruct (uri,i,j,exp_named_subst) ->
+          let params =
+           (match CicEnvironment.get_obj uri with
+               C.Constant _ -> raise ReferenceToConstant
+             | C.Variable _ -> raise ReferenceToVariable
+             | C.CurrentProof _ -> raise ReferenceToCurrentProof
+             | C.InductiveDefinition (_,params,_) -> params
+           )
+          in
+           let exp_named_subst' =
+            substaux_in_exp_named_subst params exp_named_subst m 
+           in
+            C.MutConstruct (uri,i,j,exp_named_subst')
+       | C.MutCase (sp,i,outt,t,pl) ->
+          C.MutCase (sp,i,unwind_aux m outt, unwind_aux m t,
+           List.map (unwind_aux m) pl)
+       | C.Fix (i,fl) ->
+          let len = List.length fl in
+          let substitutedfl =
+           List.map
+            (fun (name,i,ty,bo) ->
+              (name, i, unwind_aux m ty, unwind_aux (m+len) bo))
+             fl
+          in
+           C.Fix (i, substitutedfl)
+       | C.CoFix (i,fl) ->
+          let len = List.length fl in
+          let substitutedfl =
+           List.map
+            (fun (name,ty,bo) -> (name, unwind_aux m ty, unwind_aux (m+len) bo))
+             fl
+          in
+           C.CoFix (i, substitutedfl)
+     and substaux_in_exp_named_subst params exp_named_subst' m  =
+  (*CSC: Idea di Andrea di ordinare compatibilmente con l'ordine dei params
+      let ens' =
+       List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
+  (*CSC: qui liftiamo tutti gli ens anche se magari me ne servono la meta'!!! *)
+        List.map (function (uri,t) -> uri, CicSubstitution.lift m t) ens
+      in
+      let rec filter_and_lift =
+       function
+          [] -> []
+        | uri::tl ->
+           let r = filter_and_lift tl in
+            (try
+              (uri,(List.assq uri ens'))::r
+             with
+              Not_found -> r
+            )
+      in
+       filter_and_lift params
+  *)
+  
+  (*CSC: invece di concatenare sarebbe meglio rispettare l'ordine dei params *)
+  (*CSC: e' vero???? una veloce prova non sembra confermare la teoria        *)
+  
+  (*CSC: codice copiato e modificato dalla cicSubstitution.subst_vars *)
+  (*CSC: codice altamente inefficiente *)
+      let rec filter_and_lift already_instantiated =
+       function
+          [] -> []
+        | (uri,t)::tl when
+            List.for_all
+             (function (uri',_)-> not (UriManager.eq uri uri')) exp_named_subst'
+            &&
+             not (List.mem uri already_instantiated)
+            &&
+             List.mem uri params
+           ->
+            (uri,CicSubstitution.lift m (RS.from_ens t)) ::
+             (filter_and_lift (uri::already_instantiated) tl)
+        | _::tl -> filter_and_lift already_instantiated tl
 (*
-    | (uri,_)::tl ->
+        | (uri,_)::tl ->
 prerr_endline ("---- SKIPPO " ^ UriManager.string_of_uri uri) ;
 if List.for_all (function (uri',_) -> not (UriManager.eq uri uri')) exp_named_subst' then prerr_endline "---- OK1" ;
 prerr_endline ("++++ uri " ^ UriManager.string_of_uri uri ^ " not in " ^ String.concat " ; " (List.map UriManager.string_of_uri params)) ;
 if List.mem uri params then prerr_endline "---- OK2" ;
         filter_and_lift tl
 *)
-    in
-     List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
-      (filter_and_lift [] (List.rev ens))
-   in
-    unwind_aux m t          
-;;
-
-let unwind =
- unwind' 0 
-;;
-
-let reduce context : config -> Cic.term = 
- let module C = Cic in
- let module S = CicSubstitution in 
- let rec reduce =
-  function
-     (k, e, _, (C.Rel n as t), s) ->
-      let d =
-       try
-        Some (List.nth e (n-1))
-       with
-        _ ->
+      in
+       List.map (function (uri,t) -> uri, unwind_aux m t) exp_named_subst' @
+        (filter_and_lift [] (List.rev ens))
+     in
+      unwind_aux m t          
+  ;;
+  
+  let unwind =
+   unwind' 0 
+  ;;
+  
+  let reduce context : config -> Cic.term = 
+   let module C = Cic in
+   let module S = CicSubstitution in 
+   let rec reduce =
+    function
+       (k, e, _, (C.Rel n as t), s) ->
+        let d =
          try
-          begin
-           match List.nth context (n - 1 - k) with
-              None -> assert false
-            | Some (_,C.Decl _) -> None
-            | Some (_,C.Def x) -> Some (S.lift (n - k) x)
-          end
+          Some (RS.from_env (List.nth e (n-1)))
          with
-          _ -> None
-      in
-       (match d with 
-           Some t' -> reduce (0,[],[],t',s)
-         | None ->
-            if s = [] then
-             C.Rel (n-k)
-            else C.Appl (C.Rel (n-k)::s)
-       )
-   | (k, e, ens, (C.Var (uri,exp_named_subst) as t), s) -> 
-       if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
-        reduce (0, [], [], List.assq uri ens, s)
-       else
+          _ ->
+           try
+            begin
+             match List.nth context (n - 1 - k) with
+                None -> assert false
+              | Some (_,C.Decl _) -> None
+              | Some (_,C.Def x) -> Some (S.lift (n - k) x)
+            end
+           with
+            _ -> None
+        in
+         (match d with 
+             Some t' -> reduce (0,[],[],t',s)
+           | None ->
+              if s = [] then
+               C.Rel (n-k)
+              else C.Appl (C.Rel (n-k)::(RS.from_stack_list ~unwind s))
+         )
+     | (k, e, ens, (C.Var (uri,exp_named_subst) as t), s) -> 
+         if List.exists (function (uri',_) -> UriManager.eq uri' uri) ens then
+          reduce (0, [], [], RS.from_ens (List.assq uri ens), s)
+         else
+          (match CicEnvironment.get_obj uri with
+              C.Constant _ -> raise ReferenceToConstant
+            | C.CurrentProof _ -> raise ReferenceToCurrentProof
+            | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
+            | C.Variable (_,None,_,_) ->
+               let t' = unwind k e ens t in
+                if s = [] then t' else
+                 C.Appl (t'::(RS.from_stack_list ~unwind s))
+            | C.Variable (_,Some body,_,_) ->
+               let ens' = push_exp_named_subst k e ens exp_named_subst in
+                reduce (0, [], ens', body, s)
+          )
+     | (k, e, ens, (C.Meta _ as t), s) ->
+        let t' = unwind k e ens t in
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, _, (C.Sort _ as t), s) -> t (* s should be empty *)
+     | (k, e, _, (C.Implicit as t), s) -> t (* s should be empty *)
+     | (k, e, ens, (C.Cast (te,ty) as t), s) ->
+        reduce (k, e, ens, te, s) (* s should be empty *)
+     | (k, e, ens, (C.Prod _ as t), s) ->
+         unwind k e ens t (* s should be empty *)
+     | (k, e, ens, (C.Lambda (_,_,t) as t'), []) -> unwind k e ens t' 
+     | (k, e, ens, C.Lambda (_,_,t), p::s) ->
+         reduce (k+1, (RS.stack_to_env ~reduce ~unwind p)::e, ens, t,s)
+     | (k, e, ens, (C.LetIn (_,m,t) as t'), s) ->
+        let m' = RS.compute_to_env ~reduce ~unwind k e ens m in
+         reduce (k+1, m'::e, ens, t, s)
+     | (_, _, _, C.Appl [], _) -> raise (Impossible 1)
+     | (k, e, ens, C.Appl (he::tl), s) ->
+        let tl' =
+         List.map
+          (function t -> RS.compute_to_stack ~reduce ~unwind k e ens t) tl
+        in
+         reduce (k, e, ens, he, (List.append tl') s)
+  (* CSC: Old Dead Code 
+     | (k, e, ens, C.Appl ((C.Lambda _ as he)::tl), s) 
+     | (k, e, ens, C.Appl ((C.Const _ as he)::tl), s)  
+     | (k, e, ens, C.Appl ((C.MutCase _ as he)::tl), s) 
+     | (k, e, ens, C.Appl ((C.Fix _ as he)::tl), s) ->
+  (* strict evaluation, but constants are NOT unfolded *)
+        let red =
+         function
+            C.Const _ as t -> unwind k e ens t
+          | t -> reduce (k,e,ens,t,[])
+        in
+         let tl' = List.map red tl in
+          reduce (k, e, ens, he , List.append tl' s)
+     | (k, e, ens, C.Appl l, s) ->
+         C.Appl (List.append (List.map (unwind k e ens) l) s)
+  *)
+     | (k, e, ens, (C.Const (uri,exp_named_subst) as t), s) ->
         (match CicEnvironment.get_obj uri with
-            C.Constant _ -> raise ReferenceToConstant
-          | C.CurrentProof _ -> raise ReferenceToCurrentProof
-          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-          | C.Variable (_,None,_,_) ->
+            C.Constant (_,Some body,_,_) ->
+             let ens' = push_exp_named_subst k e ens exp_named_subst in
+              (* constants are closed *)
+              reduce (0, [], ens', body, s) 
+          | C.Constant (_,None,_,_) ->
              let t' = unwind k e ens t in
-              if s = [] then t' else C.Appl (t'::s)
-          | C.Variable (_,Some body,_,_) ->
+              if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+          | C.Variable _ -> raise ReferenceToVariable
+          | C.CurrentProof (_,_,body,_,_) ->
              let ens' = push_exp_named_subst k e ens exp_named_subst in
+              (* constants are closed *)
               reduce (0, [], ens', body, s)
+          | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
         )
-   | (k, e, ens, (C.Meta _ as t), s) ->
-      let t' = unwind k e ens t in
-       if s = [] then t' else C.Appl (t'::s)
-   | (k, e, _, (C.Sort _ as t), s) -> t (* s should be empty *)
-   | (k, e, _, (C.Implicit as t), s) -> t (* s should be empty *)
-   | (k, e, ens, (C.Cast (te,ty) as t), s) ->
-      reduce (k, e, ens, te, s) (* s should be empty *)
-   | (k, e, ens, (C.Prod _ as t), s) -> unwind k e ens t (* s should be empty *)
-   | (k, e, ens, (C.Lambda (_,_,t) as t'), []) -> unwind k e ens t' 
-   | (k, e, ens, C.Lambda (_,_,t), p::s) ->
-       reduce (k+1, p::e, ens, t,s) 
-   (* lazy *)
-   | (k, e, ens, (C.LetIn (_,m,t) as t'), s) when call_by_name ->
-      let m' = unwind k e ens m in reduce (k+1, m'::e, ens, t, s)
-   (* strict *)
-   | (k, e, ens, (C.LetIn (_,m,t) as t'), s) ->
-      let m' = reduce (k,e,ens,m,[]) in reduce (k+1,m'::e,ens,t,s)
-   | (_, _, _, C.Appl [], _) -> raise (Impossible 1)
-   (* lazy *)
-   | (k, e, ens, C.Appl (he::tl), s) when call_by_name ->
-      let tl' = List.map (unwind k e ens) tl in
-       reduce (k, e, ens, he, (List.append tl' s))
-   (* strict, but constants are NOT unfolded *)
-   | (k, e, ens, C.Appl (he::tl), s) ->
-      (* constants are NOT unfolded *)
-      let red =
-       function
-          C.Const _ as t -> unwind k e ens t    
-        | t -> reduce (k,e,ens,t,[])
-      in
-       let tl' = List.map red tl in
-        reduce (k, e, ens, he , List.append tl' s) 
-(* 
-   | (k, e, ens, C.Appl ((C.Lambda _ as he)::tl), s) 
-   | (k, e, ens, C.Appl ((C.Const _ as he)::tl), s)  
-   | (k, e, ens, C.Appl ((C.MutCase _ as he)::tl), s) 
-   | (k, e, ens, C.Appl ((C.Fix _ as he)::tl), s) ->
-(* strict evaluation, but constants are NOT unfolded *)
-      let red =
-       function
-          C.Const _ as t -> unwind k e ens t
-        | t -> reduce (k,e,ens,t,[])
-      in
-       let tl' = List.map red tl in
-        reduce (k, e, ens, he , List.append tl' s)
-   | (k, e, ens, C.Appl l, s) ->
-       C.Appl (List.append (List.map (unwind k e ens) l) s)
-*)
-   | (k, e, ens, (C.Const (uri,exp_named_subst) as t), s) ->
-      (match CicEnvironment.get_obj uri with
-          C.Constant (_,Some body,_,_) ->
-           let ens' = push_exp_named_subst k e ens exp_named_subst in
-            (* constants are closed *)
-            reduce (0, [], ens', body, s) 
-        | C.Constant (_,None,_,_) ->
-           let t' = unwind k e ens t in
-            if s = [] then t' else C.Appl (t'::s)
-        | C.Variable _ -> raise ReferenceToVariable
-        | C.CurrentProof (_,_,body,_,_) ->
-           let ens' = push_exp_named_subst k e ens exp_named_subst in
-            (* constants are closed *)
-            reduce (0, [], ens', body, s)
-        | C.InductiveDefinition _ -> raise ReferenceToInductiveDefinition
-      )
-   | (k, e, ens, (C.MutInd _ as t),s) ->
-      let t' = unwind k e ens t in 
-       if s = [] then t' else C.Appl (t'::s)
-   | (k, e, ens, (C.MutConstruct _ as t),s) -> 
-       let t' = unwind k e ens t in
-        if s = [] then t' else C.Appl (t'::s)
-   | (k, e, ens, (C.MutCase (mutind,i,_,term,pl) as t),s) ->
-      let decofix =
-       function
-          C.CoFix (i,fl) as t ->
-           let (_,_,body) = List.nth fl i in
-            let body' =
-             let counter = ref (List.length fl) in
-              List.fold_right
-               (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
-               fl
-               body
-            in
-             (* the term is the result of a reduction; *)
-             (* so it is already unwinded.             *)
-             reduce (0,[],[],body',[])
-        | C.Appl (C.CoFix (i,fl) :: tl) ->
-           let (_,_,body) = List.nth fl i in
-            let body' =
-             let counter = ref (List.length fl) in
-              List.fold_right
-               (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
-               fl
-               body
-            in
-             (* the term is the result of a reduction; *)
-             (* so it is already unwinded.             *)
-             reduce (0,[],[],body',tl)
-        | t -> t
-      in
-       (match decofix (reduce (k,e,ens,term,[])) with
-           C.MutConstruct (_,_,j,_) ->
-            reduce (k, e, ens, (List.nth pl (j-1)), s)
-         | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
-            let (arity, r) =
-             match CicEnvironment.get_obj mutind with
-                C.InductiveDefinition (tl,ingredients,r) ->
-                  let (_,_,arity,_) = List.nth tl i in
-                   (arity,r)
-              | _ -> raise WrongUriToInductiveDefinition
-            in
-             let ts =
-              let num_to_eat = r in
-               let rec eat_first =
-                function
-                   (0,l) -> l
-                 | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
-                 | _ -> raise (Impossible 5)
+     | (k, e, ens, (C.MutInd _ as t),s) ->
+        let t' = unwind k e ens t in 
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, ens, (C.MutConstruct _ as t),s) -> 
+         let t' = unwind k e ens t in
+          if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+     | (k, e, ens, (C.MutCase (mutind,i,_,term,pl) as t),s) ->
+        let decofix =
+         function
+            C.CoFix (i,fl) as t ->
+             let (_,_,body) = List.nth fl i in
+              let body' =
+               let counter = ref (List.length fl) in
+                List.fold_right
+                 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
+                 fl
+                 body
+              in
+               (* the term is the result of a reduction; *)
+               (* so it is already unwinded.             *)
+               reduce (0,[],[],body',[])
+          | C.Appl (C.CoFix (i,fl) :: tl) ->
+             let (_,_,body) = List.nth fl i in
+              let body' =
+               let counter = ref (List.length fl) in
+                List.fold_right
+                 (fun _ -> decr counter ; S.subst (C.CoFix (!counter,fl)))
+                 fl
+                 body
+              in
+               (* the term is the result of a reduction; *)
+               (* so it is already unwinded.             *)
+               reduce (0,[],[],body',RS.to_stack_list tl)
+          | t -> t
+        in
+         (match decofix (reduce (k,e,ens,term,[])) with
+             C.MutConstruct (_,_,j,_) ->
+              reduce (k, e, ens, (List.nth pl (j-1)), s)
+           | C.Appl (C.MutConstruct (_,_,j,_) :: tl) ->
+              let (arity, r) =
+               match CicEnvironment.get_obj mutind with
+                  C.InductiveDefinition (tl,ingredients,r) ->
+                    let (_,_,arity,_) = List.nth tl i in
+                     (arity,r)
+                | _ -> raise WrongUriToInductiveDefinition
+              in
+               let ts =
+                let num_to_eat = r in
+                 let rec eat_first =
+                  function
+                     (0,l) -> l
+                   | (n,he::tl) when n > 0 -> eat_first (n - 1, tl)
+                   | _ -> raise (Impossible 5)
+                 in
+                  eat_first (num_to_eat,tl)
                in
-                eat_first (num_to_eat,tl)
-             in
-              (* ts are already unwinded because they are a sublist of tl *)
-              reduce (k, e, ens, (List.nth pl (j-1)),(ts@s)) 
-        | C.Cast _ | C.Implicit ->
-            raise (Impossible 2) (* we don't trust our whd ;-) *)
-         | _ ->
-           let t' = unwind k e ens t in
-            if s = [] then t' else C.Appl (t'::s)
-       )
-   | (k, e, ens, (C.Fix (i,fl) as t), s) ->
-      let (_,recindex,_,body) = List.nth fl i in
-       let recparam =
-        try
-         Some (List.nth s recindex)
-        with
-         _ -> None
-       in
-        (match recparam with
-            Some recparam ->
-             (match reduce (0,[],[],recparam,[]) with
-                 (* match recparam with *) 
-                 C.MutConstruct _
-               | C.Appl ((C.MutConstruct _)::_) ->
-                  (* OLD 
-                  let body' =
-                   let counter = ref (List.length fl) in
-                    List.fold_right
-                     (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
-                     fl
-                     body
-                  in 
-                   reduce (k, e, ens, body', s) *)
-                  (* NEW *)
-                  let leng = List.length fl in
-                  let fl' = 
-                   let unwind_fl (name,recindex,typ,body) = 
-                    (name,recindex,unwind k e ens typ,
-                      unwind' leng k e ens body)
-                   in
-                   List.map unwind_fl fl
-                  in
-                   let new_env =
-                    let counter = ref 0 in
-                    let rec build_env e =
-                     if !counter = leng then e
-                     else
-                      (incr counter ; build_env ((C.Fix (!counter -1, fl'))::e))
+                (* ts are already unwinded because they are a sublist of tl *)
+                reduce (k, e, ens, (List.nth pl (j-1)), (RS.to_stack_list ts)@s)
+          | C.Cast _ | C.Implicit ->
+              raise (Impossible 2) (* we don't trust our whd ;-) *)
+           | _ ->
+             let t' = unwind k e ens t in
+              if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+         )
+     | (k, e, ens, (C.Fix (i,fl) as t), s) ->
+        let (_,recindex,_,body) = List.nth fl i in
+         let recparam =
+          try
+           Some (RS.from_stack ~unwind (List.nth s recindex))
+          with
+           _ -> None
+         in
+          (match recparam with
+              Some recparam ->
+               (match reduce (0,[],[],recparam,[]) with
+                   (* match recparam with *) 
+                   C.MutConstruct _
+                 | C.Appl ((C.MutConstruct _)::_) ->
+                    (* OLD 
+                    let body' =
+                     let counter = ref (List.length fl) in
+                      List.fold_right
+                       (fun _ -> decr counter ; S.subst (C.Fix (!counter,fl)))
+                       fl
+                       body
+                    in 
+                     reduce (k, e, ens, body', s) *)
+                    (* NEW *)
+                    let leng = List.length fl in
+                    let fl' = 
+                     let unwind_fl (name,recindex,typ,body) = 
+                      (name,recindex,unwind k e ens typ,
+                        unwind' leng k e ens body)
+                     in
+                     List.map unwind_fl fl
                     in
-                     build_env e
-                   in
-                    reduce (k+leng, new_env, ens, body, s)  
-               | _ ->
-                 let t' = unwind k e ens t in 
-                  if s = [] then t' else C.Appl (t'::s)
-             )
-          | None ->
-             let t' = unwind k e ens t in 
-              if s = [] then t' else C.Appl (t'::s)
-        )
-   | (k, e, ens, (C.CoFix (i,fl) as t),s) ->
-      let t' = unwind k e ens t in 
-       if s = [] then t' else C.Appl (t'::s)
- and push_exp_named_subst k e ens =
-  function
-     [] -> ens
-   | (uri,t)::tl -> push_exp_named_subst k e ((uri,unwind k e ens t)::ens) tl
- in
-  reduce
-;;
-
-let rec whd context t = reduce context (0, [], [], t, []);;
-
+                     let new_env =
+                      let counter = ref 0 in
+                      let rec build_env e =
+                       if !counter = leng then e
+                       else
+                        (incr counter ;
+                         build_env ((RS.to_env (C.Fix (!counter -1, fl')))::e))
+                      in
+                       build_env e
+                     in
+                      reduce (k+leng, new_env, ens, body, s)  
+                 | _ ->
+                   let t' = unwind k e ens t in 
+                    if s = [] then t' else
+                     C.Appl (t'::(RS.from_stack_list ~unwind s))
+               )
+            | None ->
+               let t' = unwind k e ens t in 
+                if s = [] then t' else
+                 C.Appl (t'::(RS.from_stack_list ~unwind s))
+          )
+     | (k, e, ens, (C.CoFix (i,fl) as t),s) ->
+        let t' = unwind k e ens t in 
+         if s = [] then t' else C.Appl (t'::(RS.from_stack_list ~unwind s))
+   and push_exp_named_subst k e ens =
+    function
+       [] -> ens
+     | (uri,t)::tl ->
+         push_exp_named_subst k e ((uri,RS.to_ens (unwind k e ens t))::ens) tl
+   in
+    reduce
+  ;;
+  
+  let rec whd context t = reduce context (0, [], [], t, []);;
+  
 (* DEBUGGING ONLY
 let whd context t =
  let res = whd context t in
@@ -481,7 +748,26 @@ let _ =  CicReductionNaif.are_convertible context res rescsc in
    res
 ;;
 *)
+ end
+;;
+
+
+(*
+module R = Reduction CallByNameStrategy;;
+module R = Reduction CallByValueStrategy;;
+module R = Reduction CallByValueStrategyByNameOnConstants;;
+module R = Reduction LazyCallByValueStrategy;;
+module R = Reduction LazyCallByValueStrategyByNameOnConstants;;
+module R = Reduction LazyCallByNameStrategy;;
+module R = Reduction
+ LazyCallByValueByNameOnConstantsWhenFromStack_ByNameStrategyWhenFromEnvOrEns;;
+module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;;
+module R = Reduction
+ ClosuresOnStackByValueFromEnvOrEnsByNameOnConstantsStrategy;;
+*)
+module R = Reduction ClosuresOnStackByValueFromEnvOrEnsStrategy;;
 
+let whd = R.whd;;
 
 (* t1, t2 must be well-typed *)
 let are_convertible =