]> matita.cs.unibo.it Git - helm.git/commitdiff
added is_closed to nCicUtils.
authorEnrico Tassi <enrico.tassi@inria.fr>
Thu, 27 Mar 2008 13:45:29 +0000 (13:45 +0000)
committerEnrico Tassi <enrico.tassi@inria.fr>
Thu, 27 Mar 2008 13:45:29 +0000 (13:45 +0000)
partial implementation of the typeof main function.
dummy nCicPp waiting for a proper replacement

helm/software/components/ng_kernel/.depend
helm/software/components/ng_kernel/nCicPp.ml [new file with mode: 0644]
helm/software/components/ng_kernel/nCicPp.mli [new file with mode: 0644]
helm/software/components/ng_kernel/nCicTypeChecker.ml
helm/software/components/ng_kernel/nCicTypeChecker.mli
helm/software/components/ng_kernel/nCicUtils.ml
helm/software/components/ng_kernel/nCicUtils.mli

index 77deeaeec4da316be4d587c80cfc3ea2980ad132..a6a0a07f6f7f270a4920dfca5b6fba3bfe63d830 100644 (file)
@@ -1,30 +1,33 @@
-nCicEnvironment.cmi: nUri.cmi nReference.cmi nCic.cmo 
-nCicTypeChecker.cmi: nCic.cmo 
 nReference.cmi: nUri.cmi 
 oCic2NCic.cmi: nCic.cmo 
-nCicSubstitution.cmi: nCic.cmo 
+nCicEnvironment.cmi: nUri.cmi nReference.cmi nCic.cmo 
+nCicTypeChecker.cmi: nCic.cmo 
 nCicUtils.cmi: nCic.cmo 
+nCicSubstitution.cmi: nCic.cmo 
+nCicReduction.cmi: nCic.cmo 
 nCic2OCic.cmi: nCic.cmo 
 nCic.cmo: nUri.cmi nReference.cmi 
 nCic.cmx: nUri.cmx nReference.cmx 
+nUri.cmo: nUri.cmi 
+nUri.cmx: nUri.cmi 
+nReference.cmo: nUri.cmi nReference.cmi 
+nReference.cmx: nUri.cmx nReference.cmi 
+oCic2NCic.cmo: nUri.cmi nReference.cmi nCic.cmo oCic2NCic.cmi 
+oCic2NCic.cmx: nUri.cmx nReference.cmx nCic.cmx oCic2NCic.cmi 
 nCicEnvironment.cmo: oCic2NCic.cmi nUri.cmi nReference.cmi nCic.cmo \
     nCicEnvironment.cmi 
 nCicEnvironment.cmx: oCic2NCic.cmx nUri.cmx nReference.cmx nCic.cmx \
     nCicEnvironment.cmi 
-nCicTypeChecker.cmo: nCicTypeChecker.cmi 
-nCicTypeChecker.cmx: nCicTypeChecker.cmi 
-nReference.cmo: nUri.cmi nReference.cmi 
-nReference.cmx: nUri.cmx nReference.cmi 
+nCicTypeChecker.cmo: nCicUtils.cmi nCicSubstitution.cmi nCicReduction.cmi \
+    nCicPp.cmi nCic.cmo nCicTypeChecker.cmi 
+nCicTypeChecker.cmx: nCicUtils.cmx nCicSubstitution.cmx nCicReduction.cmx \
+    nCicPp.cmx nCic.cmx nCicTypeChecker.cmi 
 oCicTypeChecker.cmo: oCic2NCic.cmi nCicTypeChecker.cmi oCicTypeChecker.cmi 
 oCicTypeChecker.cmx: oCic2NCic.cmx nCicTypeChecker.cmx oCicTypeChecker.cmi 
-oCic2NCic.cmo: nUri.cmi nReference.cmi nCic.cmo oCic2NCic.cmi 
-oCic2NCic.cmx: nUri.cmx nReference.cmx nCic.cmx oCic2NCic.cmi 
-nUri.cmo: nUri.cmi 
-nUri.cmx: nUri.cmi 
-nCicSubstitution.cmo: nCicUtils.cmi nCic.cmo nCicSubstitution.cmi 
-nCicSubstitution.cmx: nCicUtils.cmx nCic.cmx nCicSubstitution.cmi 
 nCicUtils.cmo: nCic.cmo nCicUtils.cmi 
 nCicUtils.cmx: nCic.cmx nCicUtils.cmi 
+nCicSubstitution.cmo: nCicUtils.cmi nCic.cmo nCicSubstitution.cmi 
+nCicSubstitution.cmx: nCicUtils.cmx nCic.cmx nCicSubstitution.cmi 
 nCicReduction.cmo: nReference.cmi nCicUtils.cmi nCicSubstitution.cmi \
     nCicEnvironment.cmi nCic.cmo nCicReduction.cmi 
 nCicReduction.cmx: nReference.cmx nCicUtils.cmx nCicSubstitution.cmx \
diff --git a/helm/software/components/ng_kernel/nCicPp.ml b/helm/software/components/ng_kernel/nCicPp.ml
new file mode 100644 (file)
index 0000000..a792e86
--- /dev/null
@@ -0,0 +1 @@
+let ppterm t = "TODO";;
diff --git a/helm/software/components/ng_kernel/nCicPp.mli b/helm/software/components/ng_kernel/nCicPp.mli
new file mode 100644 (file)
index 0000000..3aa3c02
--- /dev/null
@@ -0,0 +1 @@
+val ppterm: NCic.term -> string
index 9b528b7651c6c225849ed6fa1b03872a9038a4b3..b5a4ab583c2a27cb1c688b800f5859c5f4bb90cc 100644 (file)
@@ -2272,5 +2272,429 @@ Deannotate.type_of_aux' := fun context t -> fst (type_of_aux' [] context t CicUn
 
 *)
 
+module C = NCic 
+module R = NCicReduction
+module S = NCicSubstitution 
+module U = NCicUtils
+
+
+let sort_of_prod ~subst context (name,s) (t1, t2) =
+   let t1 = R.whd ~subst context t1 in
+   let t2 = R.whd ~subst ((name,C.Decl s)::context) t2 in
+   match t1, t2 with
+   | C.Sort s1, C.Sort s2
+      (* different from Coq manual, Impredicative Set! *)
+      when (s2 = C.Prop || s2 = C.Set || s2 = C.CProp) -> C.Sort s2
+   | C.Sort (C.Type t1), C.Sort (C.Type t2) -> C.Sort (C.Type (max t1 t2)) 
+   | C.Sort _,C.Sort (C.Type t1) -> C.Sort (C.Type t1)
+   | C.Meta _, C.Sort _ -> t2
+   | C.Meta _, ((C.Meta _) as t)
+   | C.Sort _, ((C.Meta _) as t) when U.is_closed t -> t2
+   | _ -> 
+      raise (TypeCheckerFailure (lazy (Printf.sprintf
+        "Prod: expected two sorts, found = %s, %s" 
+         (NCicPp.ppterm t1) (NCicPp.ppterm t2))))
+;;
+
+
+let typeof ~subst ~metasenv context term =
+  let rec aux context = function
+    | C.Rel n ->
+       (try
+         match List.nth context (n - 1) with
+         | (_,C.Decl ty) -> S.lift n ty
+         | (_,C.Def (_,ty)) -> S.lift n ty
+        with Failure _ -> raise (TypeCheckerFailure (lazy "unbound variable")))
+    | C.Sort (C.Type i) -> C.Sort (C.Type (i+1))
+    | C.Sort s -> C.Sort (C.Type 0)
+    | C.Implicit _ -> raise (AssertFailure (lazy "Implicit found"))
+    | C.Prod (name,s,t) ->
+       let sort1 = aux context s in
+       let sort2 = aux ((name,(C.Decl s))::context) t in
+       sort_of_prod ~subst context (name,s) (sort1,sort2)
+    | C.Lambda (n,s,t) ->
+       let sort1 = aux context s in
+       (match R.whd ~subst context sort1 with
+       | C.Meta _ | C.Sort _ -> ()
+       | _ ->
+         raise
+           (TypeCheckerFailure (lazy (Printf.sprintf
+             ("Not well-typed lambda-abstraction: " ^^
+             "the source %s should be a type; instead it is a term " ^^ 
+             "of type %s") (NCicPp.ppterm s) (NCicPp.ppterm sort1)))));
+       let type2 = 
+        aux ((n,(C.Decl s))::context) t
+       in
+        C.Prod (n,s,type2)
+    | C.LetIn (n,ty,t,bo) ->
+       let ty_t = aux context t in
+       if not (R.are_convertible ~subst ~metasenv context ty ty_t) then
+         raise 
+          (TypeCheckerFailure 
+            (lazy (Printf.sprintf
+              "The type of %s is %s but it is expected to be %s" 
+                (NCicPp.ppterm t) (NCicPp.ppterm ty_t) (NCicPp.ppterm ty))))
+       else
+         (* Alternatives: 
+           1) The type of a LetIn is a LetIn, extremely slow since the computed
+              LetIn may be later reduced.
+           2) The type of the LetIn is reduced, much faster than the previous
+              solution, moreover the inferred type is probably very different
+              from the expected one.
+           3) One-step LetIn reduction, even faster than the previous solution,
+              moreover the inferred type is closer to the expected one. *)
+         let ty_bo = aux  ((n,C.Def (t,ty))::context) bo in
+         S.subst ~avoid_beta_redexes:true t ty_bo
+ in 
+   aux context term
+(*
+    | C.Meta (n,l) -> 
+       (try
+          let (canonical_context,term,ty) = CicUtil.lookup_subst n subst in
+          let ugraph1 =
+           check_metasenv_consistency ~logger
+             ~subst metasenv context canonical_context l ugraph
+         in
+            (* assuming subst is well typed !!!!! *)
+            ((CicSubstitution.subst_meta l ty), ugraph1)
+              (* type_of_aux context (CicSubstitution.subst_meta l term) *)
+       with CicUtil.Subst_not_found _ ->
+         let (_,canonical_context,ty) = CicUtil.lookup_meta n metasenv in
+          let ugraph1 = 
+           check_metasenv_consistency ~logger
+             ~subst metasenv context canonical_context l ugraph
+         in
+            ((CicSubstitution.subst_meta l ty),ugraph1))
+   | C.Appl (he::tl) when List.length tl > 0 ->
+       let hetype,ugraph1 = type_of_aux ~logger context he ugraph in
+       let tlbody_and_type,ugraph2 = 
+        List.fold_right (
+          fun x (l,ugraph) -> 
+            let ty,ugraph1 = type_of_aux ~logger context x ugraph in
+            (*let _,ugraph1 = type_of_aux ~logger  context ty ugraph1 in*)
+              ((x,ty)::l,ugraph1)) 
+          tl ([],ugraph1) 
+       in
+        (* TASSI: questa c'era nel mio... ma non nel CVS... *)
+        (* let _,ugraph2 = type_of_aux context hetype ugraph2 in *)
+        eat_prods ~subst context hetype tlbody_and_type ugraph2
+   | C.Appl _ -> raise (AssertFailure (lazy "Appl: no arguments"))
+   | C.Const (uri,exp_named_subst) ->
+       incr fdebug ;
+       let ugraph1 = 
+        check_exp_named_subst ~logger ~subst  context exp_named_subst ugraph 
+       in
+       let cty,ugraph2 = type_of_constant ~logger uri ugraph1 in
+       let cty1 =
+        CicSubstitution.subst_vars exp_named_subst cty
+       in
+        decr fdebug ;
+        cty1,ugraph2
+   | C.MutInd (uri,i,exp_named_subst) ->
+      incr fdebug ;
+       let ugraph1 = 
+        check_exp_named_subst ~logger  ~subst context exp_named_subst ugraph 
+       in
+        (* TASSI: da me c'era anche questa, ma in CVS no *)
+       let mty,ugraph2 = type_of_mutual_inductive_defs ~logger uri i ugraph1 in
+        (* fine parte dubbia *)
+       let cty =
+        CicSubstitution.subst_vars exp_named_subst mty
+       in
+        decr fdebug ;
+        cty,ugraph2
+   | C.MutConstruct (uri,i,j,exp_named_subst) ->
+       let ugraph1 = 
+        check_exp_named_subst ~logger ~subst context exp_named_subst ugraph 
+       in
+        (* TASSI: idem come sopra *)
+       let mty,ugraph2 = 
+        type_of_mutual_inductive_constr ~logger uri i j ugraph1 
+       in
+       let cty =
+        CicSubstitution.subst_vars exp_named_subst mty
+       in
+        cty,ugraph2
+   | C.MutCase (uri,i,outtype,term,pl) ->
+      let outsort,ugraph1 = type_of_aux ~logger context outtype ugraph in
+      let (need_dummy, k) =
+      let rec guess_args context t =
+        let outtype = CicReduction.whd ~subst context t in
+          match outtype with
+              C.Sort _ -> (true, 0)
+            | C.Prod (name, s, t) ->
+               let (b, n) = 
+                 guess_args ((Some (name,(C.Decl s)))::context) t in
+                 if n = 0 then
+                 (* last prod before sort *)
+                   match CicReduction.whd ~subst context s with
+(*CSC: for _ see comment below about the missing named_exp_subst ?????????? *)
+                       C.MutInd (uri',i',_) when U.eq uri' uri && i' = i ->
+                         (false, 1)
+(*CSC: for _ see comment below about the missing named_exp_subst ?????????? *)
+                     | C.Appl ((C.MutInd (uri',i',_)) :: _)
+                         when U.eq uri' uri && i' = i -> (false, 1)
+                     | _ -> (true, 1)
+                 else
+                   (b, n + 1)
+            | _ ->
+               raise 
+                 (TypeCheckerFailure 
+                    (lazy (sprintf
+                       "Malformed case analasys' output type %s" 
+                       (CicPp.ppterm outtype))))
+      in
+(*
+      let (parameters, arguments, exp_named_subst),ugraph2 =
+       let ty,ugraph2 = type_of_aux context term ugraph1 in
+          match R.whd ~subst context ty with
+           (*CSC manca il caso dei CAST *)
+(*CSC: ma servono i parametri (uri,i)? Se si', perche' non serve anche il *)
+(*CSC: parametro exp_named_subst? Se no, perche' non li togliamo?         *)
+(*CSC: Hint: nella DTD servono per gli stylesheet.                        *)
+              C.MutInd (uri',i',exp_named_subst) as typ ->
+               if U.eq uri uri' && i = i' then 
+                 ([],[],exp_named_subst),ugraph2
+               else 
+                 raise 
+                   (TypeCheckerFailure 
+                     (lazy (sprintf
+                         ("Case analysys: analysed term type is %s, but is expected to be (an application of) %s#1/%d{_}")
+                         (CicPp.ppterm typ) (U.string_of_uri uri) i)))
+            | C.Appl 
+               ((C.MutInd (uri',i',exp_named_subst) as typ):: tl) as typ' ->
+               if U.eq uri uri' && i = i' then
+                 let params,args =
+                   split tl (List.length tl - k)
+                 in (params,args,exp_named_subst),ugraph2
+               else 
+                 raise 
+                   (TypeCheckerFailure 
+                     (lazy (sprintf 
+                         ("Case analysys: analysed term type is %s, "^
+                          "but is expected to be (an application of) "^
+                          "%s#1/%d{_}")
+                         (CicPp.ppterm typ') (U.string_of_uri uri) i)))
+            | _ ->
+               raise 
+                 (TypeCheckerFailure 
+                   (lazy (sprintf
+                       ("Case analysis: "^
+                        "analysed term %s is not an inductive one")
+                       (CicPp.ppterm term))))
+*)
+      let (b, k) = guess_args context outsort in
+         if not b then (b, k - 1) else (b, k) in
+      let (parameters, arguments, exp_named_subst),ugraph2 =
+       let ty,ugraph2 = type_of_aux ~logger context term ugraph1 in
+        match R.whd ~subst context ty with
+            C.MutInd (uri',i',exp_named_subst) as typ ->
+              if U.eq uri uri' && i = i' then 
+               ([],[],exp_named_subst),ugraph2
+              else raise 
+               (TypeCheckerFailure 
+                 (lazy (sprintf
+                     ("Case analysys: analysed term type is %s (%s#1/%d{_}), but is expected to be (an application of) %s#1/%d{_}")
+                     (CicPp.ppterm typ) (U.string_of_uri uri') i' (U.string_of_uri uri) i)))
+          | C.Appl ((C.MutInd (uri',i',exp_named_subst) as typ):: tl) ->
+              if U.eq uri uri' && i = i' then
+               let params,args =
+                 split tl (List.length tl - k)
+               in (params,args,exp_named_subst),ugraph2
+              else raise 
+               (TypeCheckerFailure 
+                 (lazy (sprintf
+                     ("Case analysys: analysed term type is %s (%s#1/%d{_}), but is expected to be (an application of) %s#1/%d{_}")
+                     (CicPp.ppterm typ) (U.string_of_uri uri') i' (U.string_of_uri uri) i)))
+          | _ ->
+              raise 
+               (TypeCheckerFailure 
+                 (lazy (sprintf
+                     "Case analysis: analysed term %s is not an inductive one"
+                      (CicPp.ppterm term))))
+      in
+       (* 
+          let's control if the sort elimination is allowed: 
+          [(I q1 ... qr)|B] 
+       *)
+      let sort_of_ind_type =
+        if parameters = [] then
+          C.MutInd (uri,i,exp_named_subst)
+        else
+          C.Appl ((C.MutInd (uri,i,exp_named_subst))::parameters)
+      in
+      let type_of_sort_of_ind_ty,ugraph3 = 
+       type_of_aux ~logger context sort_of_ind_type ugraph2 in
+      let b,ugraph4 = 
+       check_allowed_sort_elimination ~subst ~metasenv ~logger  context uri i
+          need_dummy sort_of_ind_type type_of_sort_of_ind_ty outsort ugraph3 
+      in
+       if not b then
+        raise
+          (TypeCheckerFailure (lazy ("Case analysis: sort elimination not allowed")));
+        (* let's check if the type of branches are right *)
+      let parsno,constructorsno =
+        let obj,_ =
+          try
+            CicEnvironment.get_cooked_obj ~trust:false CicUniv.empty_ugraph uri
+          with Not_found -> assert false
+        in
+        match obj with
+            C.InductiveDefinition (il,_,parsno,_) ->
+             let _,_,_,cl =
+              try List.nth il i with Failure _ -> assert false
+             in
+              parsno, List.length cl
+          | _ ->
+              raise (TypeCheckerFailure
+                (lazy ("Unknown mutual inductive definition:" ^
+                  UriManager.string_of_uri uri)))
+      in
+      if List.length pl <> constructorsno then
+       raise (TypeCheckerFailure
+        (lazy ("Wrong number of cases in case analysis"))) ;
+      let (_,branches_ok,ugraph5) =
+        List.fold_left
+          (fun (j,b,ugraph) p ->
+           if b then
+              let cons =
+               if parameters = [] then
+                 (C.MutConstruct (uri,i,j,exp_named_subst))
+               else
+                 (C.Appl 
+                    (C.MutConstruct (uri,i,j,exp_named_subst)::parameters))
+              in
+             let ty_p,ugraph1 = type_of_aux ~logger context p ugraph in
+             let ty_cons,ugraph3 = type_of_aux ~logger context cons ugraph1 in
+             (* 2 is skipped *)
+             let ty_branch = 
+               type_of_branch ~subst context parsno need_dummy outtype cons 
+                 ty_cons in
+             let b1,ugraph4 =
+               R.are_convertible 
+                 ~subst ~metasenv context ty_p ty_branch ugraph3 
+             in 
+(* Debugging code
+if not b1 then
+begin
+prerr_endline ("\n!OUTTYPE= " ^ CicPp.ppterm outtype);
+prerr_endline ("!CONS= " ^ CicPp.ppterm cons);
+prerr_endline ("!TY_CONS= " ^ CicPp.ppterm ty_cons);
+prerr_endline ("#### " ^ CicPp.ppterm ty_p ^ "\n<==>\n" ^ CicPp.ppterm ty_branch);
+end;
+*)
+             if not b1 then
+               debug_print (lazy
+                 ("#### " ^ CicPp.ppterm ty_p ^ 
+                 " <==> " ^ CicPp.ppterm ty_branch));
+             (j + 1,b1,ugraph4)
+           else
+             (j,false,ugraph)
+          ) (1,true,ugraph4) pl
+         in
+          if not branches_ok then
+           raise
+            (TypeCheckerFailure (lazy "Case analysys: wrong branch type"));
+          let arguments' =
+           if not need_dummy then outtype::arguments@[term]
+           else outtype::arguments in
+          let outtype =
+           if need_dummy && arguments = [] then outtype
+           else CicReduction.head_beta_reduce (C.Appl arguments')
+          in
+           outtype,ugraph5
+   | C.Fix (i,fl) ->
+      let types,kl,ugraph1,len =
+        List.fold_left
+          (fun (types,kl,ugraph,len) (n,k,ty,_) ->
+            let _,ugraph1 = type_of_aux ~logger context ty ugraph in
+             (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::types,
+              k::kl,ugraph1,len+1)
+         ) ([],[],ugraph,0) fl
+      in
+      let ugraph2 = 
+       List.fold_left
+          (fun ugraph (name,x,ty,bo) ->
+            let ty_bo,ugraph1 = 
+              type_of_aux ~logger (types@context) bo ugraph 
+            in
+            let b,ugraph2 = 
+              R.are_convertible ~subst ~metasenv (types@context) 
+                ty_bo (CicSubstitution.lift len ty) ugraph1 in
+              if b then
+                begin
+                  let (m, eaten, context') =
+                    eat_lambdas ~subst (types @ context) (x + 1) bo
+                  in
+                    (*
+                      let's control the guarded by 
+                      destructors conditions D{f,k,x,M}
+                    *)
+                    if not (guarded_by_destructors ~subst context' eaten 
+                              (len + eaten) kl 1 [] m) then
+                      raise
+                        (TypeCheckerFailure 
+                          (lazy ("Fix: not guarded by destructors")))
+                    else
+                      ugraph2
+                end
+               else
+                raise (TypeCheckerFailure (lazy ("Fix: ill-typed bodies")))
+          ) ugraph1 fl in
+       (*CSC: controlli mancanti solo su D{f,k,x,M} *)
+      let (_,_,ty,_) = List.nth fl i in
+       ty,ugraph2
+   | C.CoFix (i,fl) ->
+       let types,ugraph1,len =
+        List.fold_left
+          (fun (l,ugraph,len) (n,ty,_) -> 
+              let _,ugraph1 = 
+               type_of_aux ~logger context ty ugraph in 
+               (Some (C.Name n,(C.Decl (CicSubstitution.lift len ty)))::l,
+                 ugraph1,len+1)
+          ) ([],ugraph,0) fl
+       in
+       let ugraph2 = 
+        List.fold_left
+           (fun ugraph (_,ty,bo) ->
+             let ty_bo,ugraph1 = 
+               type_of_aux ~logger (types @ context) bo ugraph 
+             in
+             let b,ugraph2 = 
+               R.are_convertible ~subst ~metasenv (types @ context) ty_bo
+                 (CicSubstitution.lift len ty) ugraph1 
+             in
+               if b then
+                 begin
+                   (* let's control that the returned type is coinductive *)
+                   match returns_a_coinductive ~subst context ty with
+                       None ->
+                         raise
+                         (TypeCheckerFailure
+                           (lazy "CoFix: does not return a coinductive type"))
+                     | Some uri ->
+                         (*
+                           let's control the guarded by constructors 
+                           conditions C{f,M}
+                         *)
+                         if not (guarded_by_constructors ~subst
+                              (types @ context) 0 len false bo [] uri) then
+                           raise
+                             (TypeCheckerFailure 
+                               (lazy "CoFix: not guarded by constructors"))
+                         else
+                         ugraph2
+                 end
+               else
+                 raise
+                   (TypeCheckerFailure (lazy "CoFix: ill-typed bodies"))
+           ) ugraph1 fl 
+       in
+       let (_,ty,_) = List.nth fl i in
+        ty,ugraph2
+
+*)
+;;
+
 (* typechecks the object, raising an exception if illtyped *)
 let typecheck_obj obj = match obj with _ -> ()
index 5dc181cde03372e3b1c32db49bbedbe62419182e..51aa6458d11845d67f75dcccadf77ff65211483a 100644 (file)
@@ -29,3 +29,8 @@ exception AssertFailure of string Lazy.t
 (* typechecks the object, raising an exception if illtyped *)
 val typecheck_obj : NCic.obj -> unit
 
+val typeof: 
+  subst:NCic.substitution -> metasenv:NCic.metasenv -> 
+  NCic.context -> NCic.term -> 
+    NCic.term
+
index 5d3304f60c1130028e26cc01963c00fb3780579a..0ff437347894fb4c539c9892d6b04281197ff949 100644 (file)
@@ -28,17 +28,17 @@ let lookup_subst n subst =
     List.assoc n subst
   with Not_found -> raise (Subst_not_found n)
 
-let fold f g acc = function
+let fold f g acc = function
  | NCic.Implicit _
  | NCic.Sort _
  | NCic.Const _
  | NCic.Meta _
  | NCic.Rel _ -> acc
- | NCic.Appl l -> List.fold_left f acc l
+ | NCic.Appl l -> List.fold_left (f k) acc l
  | NCic.Prod (_,s,t)
- | NCic.Lambda (_,s,t) -> f (g (f acc s)) t
- | NCic.LetIn (_,ty,t,bo) -> f (g (f (f acc ty) t)) bo
- | NCic.Match (_,oty,t,pl) -> List.fold_left f (f (f acc oty) t) pl
+ | NCic.Lambda (_,s,t) -> f (g k) (f k acc s) t
+ | NCic.LetIn (_,ty,t,bo) -> f (g k) (f k (f k acc ty) t) bo
+ | NCic.Match (_,oty,t,pl) -> List.fold_left (f k) (f k (f k acc oty) t) pl
 ;;
 
 let sharing_map f l =
@@ -75,3 +75,17 @@ let map f g k = function
      else NCic.Match(r,oty1,t1,pl1)
 ;;
 
+exception NotClosed
+
+let is_closed t = 
+  try
+    let rec aux k _ = function
+      | NCic.Rel n when n > k -> raise NotClosed
+      | NCic.Meta (_, (s, NCic.Irl n)) when not (n+s <= k) -> raise NotClosed
+      | NCic.Meta (_, (s, NCic.Ctx l)) -> List.iter (aux (k+s) ()) l 
+      | _ -> fold aux ((+) 1) () k t
+    in 
+      aux 0 () t; true
+  with NotClosed -> false
+;;
+
index 506af8c0b60773198190f0fca8492e9455c410a6..7a9ce090b8cd11773bd6492cea234e6d3f9eb2fc 100644 (file)
@@ -33,5 +33,7 @@ val lookup_subst: int ->  NCic.substitution -> NCic.subst_entry
 
 (* both Meta agnostic, map attempts to preserve sharing.
  * call the 'a->'a function when a binder is crossed *)
-val fold: ('a -> NCic.term -> 'a) -> ('a -> 'a) -> 'a -> NCic.term -> 'a
+val fold: ('a -> 'b -> NCic.term -> 'b) -> ('a -> 'a) -> 'b -> 'a -> NCic.term -> 'b
 val map: ('a -> NCic.term -> NCic.term) -> ('a -> 'a) -> 'a -> NCic.term -> NCic.term
+
+val is_closed: NCic.term -> bool