]> matita.cs.unibo.it Git - helm.git/blob - helm/ocaml/cic_unification/cicMetaSubst.ml
9695d714b7658940392fc4401af71d3701d7298f
[helm.git] / helm / ocaml / cic_unification / cicMetaSubst.ml
1 (* Copyright (C) 2004, HELM Team.
2  * 
3  * This file is part of HELM, an Hypertextual, Electronic
4  * Library of Mathematics, developed at the Computer Science
5  * Department, University of Bologna, Italy.
6  * 
7  * HELM is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * 
12  * HELM is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with HELM; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA  02111-1307, USA.
21  * 
22  * For details, see the HELM World-Wide-Web page,
23  * http://cs.unibo.it/helm/.
24  *)
25
26 open Printf
27
28 exception MetaSubstFailure of string
29 exception Uncertain of string
30 exception AssertFailure of string
31
32 let debug_print = prerr_endline
33
34 type substitution = (int * Cic.term) list
35
36 (*** Functions to apply a substitution ***)
37
38 let apply_subst_gen ~appl_fun subst term =
39  let rec um_aux =
40   let module C = Cic in
41   let module S = CicSubstitution in 
42    function
43       C.Rel _ as t -> t
44     | C.Var (uri,exp_named_subst) ->
45        let exp_named_subst' =
46          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
47        in
48        C.Var (uri, exp_named_subst')
49     | C.Meta (i, l) -> 
50         (try
51           let t = List.assoc i subst in
52           um_aux (S.lift_meta l t)
53         with Not_found -> (* not constrained variable, i.e. free in subst*)
54           let l' =
55             List.map (function None -> None | Some t -> Some (um_aux t)) l
56           in
57            C.Meta (i,l'))
58     | C.Sort _ as t -> t
59     | C.Implicit _ -> assert false
60     | C.Cast (te,ty) -> C.Cast (um_aux te, um_aux ty)
61     | C.Prod (n,s,t) -> C.Prod (n, um_aux s, um_aux t)
62     | C.Lambda (n,s,t) -> C.Lambda (n, um_aux s, um_aux t)
63     | C.LetIn (n,s,t) -> C.LetIn (n, um_aux s, um_aux t)
64     | C.Appl (hd :: tl) -> appl_fun um_aux hd tl
65     | C.Appl _ -> assert false
66     | C.Const (uri,exp_named_subst) ->
67        let exp_named_subst' =
68          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
69        in
70        C.Const (uri, exp_named_subst')
71     | C.MutInd (uri,typeno,exp_named_subst) ->
72        let exp_named_subst' =
73          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
74        in
75        C.MutInd (uri,typeno,exp_named_subst')
76     | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
77        let exp_named_subst' =
78          List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
79        in
80        C.MutConstruct (uri,typeno,consno,exp_named_subst')
81     | C.MutCase (sp,i,outty,t,pl) ->
82        let pl' = List.map um_aux pl in
83        C.MutCase (sp, i, um_aux outty, um_aux t, pl')
84     | C.Fix (i, fl) ->
85        let fl' =
86          List.map (fun (name, i, ty, bo) -> (name, i, um_aux ty, um_aux bo)) fl
87        in
88        C.Fix (i, fl')
89     | C.CoFix (i, fl) ->
90        let fl' =
91          List.map (fun (name, ty, bo) -> (name, um_aux ty, um_aux bo)) fl
92        in
93        C.CoFix (i, fl')
94  in
95  um_aux term
96 ;;
97
98 let apply_subst =
99   let appl_fun um_aux he tl =
100     let tl' = List.map um_aux tl in
101       begin
102        match um_aux he with
103           Cic.Appl l -> Cic.Appl (l@tl')
104         | he' -> Cic.Appl (he'::tl')
105       end
106   in
107   apply_subst_gen ~appl_fun
108 ;;
109
110 (* apply_subst_reducing subst (Some (mtr,reductions_no)) t              *)
111 (* performs as (apply_subst subst t) until it finds an application of   *)
112 (* (META [meta_to_reduce]) that, once unwinding is performed, creates   *)
113 (* a new beta-redex; in this case up to [reductions_no] consecutive     *)
114 (* beta-reductions are performed.                                       *)
115 (* Hint: this function is usually called when [reductions_no]           *)
116 (*  eta-expansions have been performed and the head of the new          *)
117 (*  application has been unified with (META [meta_to_reduce]):          *)
118 (*  during the unwinding the eta-expansions are undone.                 *)
119
120 let apply_subst_reducing meta_to_reduce =
121   let appl_fun um_aux he tl =
122     let tl' = List.map um_aux tl in
123     let t' =
124      match um_aux he with
125         Cic.Appl l -> Cic.Appl (l@tl')
126       | he' -> Cic.Appl (he'::tl')
127     in
128      begin
129       match meta_to_reduce, he with
130          Some (mtr,reductions_no), Cic.Meta (m,_) when m = mtr ->
131           let rec beta_reduce =
132            function
133               (n,(Cic.Appl (Cic.Lambda (_,_,t)::he'::tl'))) when n > 0 ->
134                 let he'' = CicSubstitution.subst he' t in
135                  if tl' = [] then
136                   he''
137                  else
138                   beta_reduce (n-1,Cic.Appl(he''::tl'))
139             | (_,t) -> t
140           in
141            beta_reduce (reductions_no,t')
142        | _,_ -> t'
143      end
144   in
145   apply_subst_gen ~appl_fun
146
147 let rec apply_subst_context subst context =
148   List.fold_right
149     (fun item context ->
150       match item with
151       | Some (n, Cic.Decl t) ->
152           let t' = apply_subst subst t in
153           Some (n, Cic.Decl t') :: context
154       | Some (n, Cic.Def (t, ty)) ->
155           let ty' =
156             match ty with
157             | None -> None
158             | Some ty -> Some (apply_subst subst ty)
159           in
160           let t' = apply_subst subst t in
161           Some (n, Cic.Def (t', ty')) :: context
162       | None -> None :: context)
163     context []
164
165 let apply_subst_metasenv subst metasenv =
166   List.map
167     (fun (n, context, ty) ->
168       (n, apply_subst_context subst context, apply_subst subst ty))
169     (List.filter
170       (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
171       metasenv)
172
173 (***** Pretty printing functions ******)
174
175 let ppsubst subst =
176   String.concat "\n"
177     (List.map
178       (fun (idx, term) -> Printf.sprintf "?%d := %s" idx (CicPp.ppterm term))
179       subst)
180 ;;
181
182 let ppterm subst term = CicPp.ppterm (apply_subst subst term)
183
184 let ppterm_in_context subst term name_context =
185  CicPp.pp (apply_subst subst term) name_context
186
187 let ppcontext' ?(sep = "\n") subst context =
188  let separate s = if s = "" then "" else s ^ sep in
189   List.fold_right 
190    (fun context_entry (i,name_context) ->
191      match context_entry with
192         Some (n,Cic.Decl t) ->
193          sprintf "%s%s : %s" (separate i) (CicPp.ppname n)
194           (ppterm_in_context subst t name_context), (Some n)::name_context
195       | Some (n,Cic.Def (bo,ty)) ->
196          sprintf "%s%s : %s := %s" (separate i) (CicPp.ppname n)
197           (match ty with
198               None -> "_"
199             | Some ty -> ppterm_in_context subst ty name_context)
200           (ppterm_in_context subst bo name_context), (Some n)::name_context
201        | None ->
202           sprintf "%s_ :? _" (separate i), None::name_context
203     ) context ("",[])
204
205 let ppcontext ?sep subst context = fst (ppcontext' ?sep subst context)
206
207 let ppmetasenv ?(sep = "\n") metasenv subst =
208   String.concat sep
209     (List.map
210       (fun (i, c, t) ->
211         let context,name_context = ppcontext' ~sep:"; " subst c in
212          sprintf "%s |- ?%d: %s" context i
213           (ppterm_in_context subst t name_context))
214       (List.filter
215         (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
216         metasenv))
217
218 (* From now on we recreate a kernel abstraction where substitutions are part of
219  * the calculus *)
220
221 let lift subst n term =
222   let term = apply_subst subst term in
223   try
224     CicSubstitution.lift n term
225   with e ->
226     raise (MetaSubstFailure ("Lift failure: " ^ Printexc.to_string e))
227
228 let subst subst t1 t2 =
229   let t1 = apply_subst subst t1 in
230   let t2 = apply_subst subst t2 in
231   try
232     CicSubstitution.subst t1 t2
233   with e ->
234     raise (MetaSubstFailure ("Subst failure: " ^ Printexc.to_string e))
235
236 let whd subst context term =
237   let term = apply_subst subst term in
238   let context = apply_subst_context subst context in
239   try
240     CicReduction.whd context term
241   with e ->
242     raise (MetaSubstFailure ("Weak head reduction failure: " ^
243       Printexc.to_string e))
244
245 let are_convertible subst context t1 t2 =
246   let context = apply_subst_context subst context in
247   let t1 = apply_subst subst t1 in
248   let t2 = apply_subst subst t2 in
249   CicReduction.are_convertible context t1 t2
250
251 let tempi_type_of_aux_subst = ref 0.0;;
252 let tempi_type_of_aux = ref 0.0;;
253
254 let type_of_aux' metasenv subst context term =
255 let time1 = Unix.gettimeofday () in
256   let term = apply_subst subst term in
257   let context = apply_subst_context subst context in
258   let metasenv =
259     List.map
260       (fun (i, c, t) -> (i, apply_subst_context subst c, apply_subst subst t))
261       (List.filter
262         (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
263         metasenv)
264   in
265 let time2 = Unix.gettimeofday () in
266 let res =
267   try
268     CicTypeChecker.type_of_aux' metasenv context term
269   with CicTypeChecker.TypeCheckerFailure msg ->
270     raise (MetaSubstFailure ("Type checker failure: " ^ msg))
271 in
272 let time3 = Unix.gettimeofday () in
273  tempi_type_of_aux_subst := !tempi_type_of_aux_subst +. time3 -. time1 ; 
274  tempi_type_of_aux := !tempi_type_of_aux +. time2 -. time1 ; 
275  res
276
277 (**** DELIFT ****)
278 (* the delift function takes in input a metavariable index, an ordered list of
279  * optional terms [t1,...,tn] and a term t, and substitutes every tk = Some
280  * (rel(nk)) with rel(k).  Typically, the list of optional terms is the explicit
281  * substitution that is applied to a metavariable occurrence and the result of
282  * the delift function is a term the implicit variable can be substituted with
283  * to make the term [t] unifiable with the metavariable occurrence.  In general,
284  * the problem is undecidable if we consider equivalence in place of alpha
285  * convertibility. Our implementation, though, is even weaker than alpha
286  * convertibility, since it replace the term [tk] if and only if [tk] is a Rel
287  * (missing all the other cases). Does this matter in practice?
288  * The metavariable index is the index of the metavariable that must not occur
289  * in the term (for occur check).
290  *)
291
292 exception NotInTheList;;
293
294 let position n =
295   let rec aux k =
296    function 
297        [] -> raise NotInTheList
298      | (Some (Cic.Rel m))::_ when m=n -> k
299      | _::tl -> aux (k+1) tl in
300   aux 1
301 ;;
302
303 exception Occur;;
304
305 let rec force_does_not_occur subst to_be_restricted t =
306  let module C = Cic in
307  let more_to_be_restricted = ref [] in
308  let rec aux k = function
309       C.Rel r when List.mem (r - k) to_be_restricted -> raise Occur
310     | C.Rel _
311     | C.Sort _ as t -> t
312     | C.Implicit _ -> assert false
313     | C.Meta (n, l) ->
314        (* we do not retrieve the term associated to ?n in subst since *)
315        (* in this way we can restrict if something goes wrong         *)
316        let l' =
317          let i = ref 0 in
318          List.map
319            (function t ->
320              incr i ;
321              match t with
322                 None -> None
323               | Some t ->
324                  try
325                    Some (aux k t)
326                  with Occur ->
327                    more_to_be_restricted := (n,!i) :: !more_to_be_restricted;
328                    None)
329            l
330        in
331         C.Meta (n, l')
332     | C.Cast (te,ty) -> C.Cast (aux k te, aux k ty)
333     | C.Prod (name,so,dest) -> C.Prod (name, aux k so, aux (k+1) dest)
334     | C.Lambda (name,so,dest) -> C.Lambda (name, aux k so, aux (k+1) dest)
335     | C.LetIn (name,so,dest) -> C.LetIn (name, aux k so, aux (k+1) dest)
336     | C.Appl l -> C.Appl (List.map (aux k) l)
337     | C.Var (uri,exp_named_subst) ->
338         let exp_named_subst' =
339           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
340         in
341         C.Var (uri, exp_named_subst')
342     | C.Const (uri, exp_named_subst) ->
343         let exp_named_subst' =
344           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
345         in
346         C.Const (uri, exp_named_subst')
347     | C.MutInd (uri,tyno,exp_named_subst) ->
348         let exp_named_subst' =
349           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
350         in
351         C.MutInd (uri, tyno, exp_named_subst')
352     | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
353         let exp_named_subst' =
354           List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
355         in
356         C.MutConstruct (uri, tyno, consno, exp_named_subst')
357     | C.MutCase (uri,tyno,out,te,pl) ->
358         C.MutCase (uri, tyno, aux k out, aux k te, List.map (aux k) pl)
359     | C.Fix (i,fl) ->
360        let len = List.length fl in
361        let k_plus_len = k + len in
362        let fl' =
363          List.map
364           (fun (name,j,ty,bo) -> (name, j, aux k ty, aux k_plus_len bo)) fl
365        in
366        C.Fix (i, fl')
367     | C.CoFix (i,fl) ->
368        let len = List.length fl in
369        let k_plus_len = k + len in
370        let fl' =
371          List.map
372           (fun (name,ty,bo) -> (name, aux k ty, aux k_plus_len bo)) fl
373        in
374        C.CoFix (i, fl')
375  in
376  let res = aux 0 t in
377  (!more_to_be_restricted, res)
378  
379 let rec restrict subst to_be_restricted metasenv =
380   let names_of_context_indexes context indexes =
381     String.concat ", "
382       (List.map
383         (fun i ->
384           try
385            match List.nth context i with
386            | None -> assert false
387            | Some (n, _) -> CicPp.ppname n
388           with
389            Failure _ -> assert false
390         ) indexes)
391   in
392   let force_does_not_occur_in_context to_be_restricted = function
393     | None -> [], None
394     | Some (name, Cic.Decl t) ->
395         let (more_to_be_restricted, t') =
396           force_does_not_occur subst to_be_restricted t
397         in
398         more_to_be_restricted, Some (name, Cic.Decl t')
399     | Some (name, Cic.Def (bo, ty)) ->
400         let (more_to_be_restricted, bo') =
401           force_does_not_occur subst to_be_restricted bo
402         in
403         let more_to_be_restricted, ty' =
404           match ty with
405           | None ->  more_to_be_restricted, None
406           | Some ty ->
407               let more_to_be_restricted', ty' =
408                 force_does_not_occur subst to_be_restricted ty
409               in
410               more_to_be_restricted @ more_to_be_restricted',
411               Some ty'
412         in
413         more_to_be_restricted, Some (name, Cic.Def (bo', ty'))
414   in
415   let rec erase i to_be_restricted n = function
416     | [] -> [], to_be_restricted, []
417     | hd::tl ->
418         let more_to_be_restricted,restricted,tl' =
419          erase (i+1) to_be_restricted n tl
420         in
421         let restrict_me = List.mem i restricted in
422         if restrict_me then
423          more_to_be_restricted, restricted, None:: tl'
424         else
425           (try
426             let more_to_be_restricted', hd' =
427               let delifted_restricted =
428                let rec aux =
429                 function
430                    [] -> []
431                  | j::tl when j > i -> (j - i)::aux tl
432                  | _::tl -> aux tl
433                in
434                 aux restricted
435               in
436                force_does_not_occur_in_context delifted_restricted hd
437             in
438              more_to_be_restricted @ more_to_be_restricted',
439              restricted, hd' :: tl'
440           with Occur ->
441             more_to_be_restricted, (i :: restricted), None :: tl')
442   in
443   let (more_to_be_restricted, metasenv, subst) =
444     List.fold_right
445       (fun (n, context, t) (more, metasenv, subst) ->
446         let to_be_restricted =
447           List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted)
448         in
449         let (more_to_be_restricted, restricted, context') =
450          (* just an optimization *)
451          if to_be_restricted = [] then
452           [],[],context
453          else
454           erase 1 to_be_restricted n context
455         in
456         try
457           let more_to_be_restricted', t' =
458             force_does_not_occur subst restricted t
459           in
460           let metasenv' = (n, context', t') :: metasenv in
461           (try
462             let s = List.assoc n subst in
463             try
464               let more_to_be_restricted'', s' =
465                 force_does_not_occur subst restricted s
466               in
467               let subst' = (n, s') :: (List.remove_assoc n subst) in
468               let more =
469                 more @ more_to_be_restricted @ more_to_be_restricted' @
470                   more_to_be_restricted''
471               in
472               (more, metasenv', subst')
473             with Occur ->
474               raise (MetaSubstFailure (sprintf
475                 "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since ?%d is already instantiated with %s and at least one of the hypotheses occurs in the substituted term"
476                 n (names_of_context_indexes context to_be_restricted) n
477                 (ppterm subst s)))
478            with Not_found -> (more @ more_to_be_restricted @ more_to_be_restricted', metasenv', subst))
479         with Occur ->
480           raise (MetaSubstFailure (sprintf
481             "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since metavariable's type depends on at least one of them"
482             n (names_of_context_indexes context to_be_restricted))))
483       metasenv ([], [], subst)
484   in
485   match more_to_be_restricted with
486   | [] -> (metasenv, subst)
487   | _ -> restrict subst more_to_be_restricted metasenv
488 ;;
489
490 (*CSC: maybe we should rename delift in abstract, as I did in my dissertation *)
491 let delift n subst context metasenv l t =
492  let module S = CicSubstitution in
493   let l =
494    let (_, canonical_context, _) = CicUtil.lookup_meta n metasenv in
495    List.map2 (fun ct lt ->
496      match (ct, lt) with
497      | None, _ -> None
498      | Some _, _ -> lt)
499      canonical_context l
500   in
501   let to_be_restricted = ref [] in
502   let rec deliftaux k =
503    let module C = Cic in
504     function
505        C.Rel m -> 
506          if m <=k then
507           C.Rel m   (*CSC: che succede se c'e' un Def? Dovrebbe averlo gia' *)
508                     (*CSC: deliftato la regola per il LetIn                 *)
509                     (*CSC: FALSO! La regola per il LetIn non lo fa          *)
510          else
511           (try
512             match List.nth context (m-k-1) with
513                Some (_,C.Def (t,_)) ->
514                 (*CSC: Hmmm. This bit of reduction is not in the spirit of    *)
515                 (*CSC: first order unification. Does it help or does it harm? *)
516                 deliftaux k (S.lift m t)
517              | Some (_,C.Decl t) ->
518                 C.Rel ((position (m-k) l) + k)
519              | None -> raise (MetaSubstFailure "RelToHiddenHypothesis")
520            with
521             Failure _ ->
522              raise (MetaSubstFailure "Unbound variable found in deliftaux")
523           )
524      | C.Var (uri,exp_named_subst) ->
525         let exp_named_subst' =
526          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
527         in
528          C.Var (uri,exp_named_subst')
529      | C.Meta (i, l1) as t -> 
530         if i = n then
531           raise (MetaSubstFailure (sprintf
532             "Cannot unify the metavariable ?%d with a term that has as subterm %s in which the same metavariable occurs (occur check)"
533             i (ppterm subst t)))
534         else
535          (* I do not consider the term associated to ?i in subst since *)
536          (* in this way I can restrict if something goes wrong.        *)
537           let rec deliftl j =
538            function
539               [] -> []
540             | None::tl -> None::(deliftl (j+1) tl)
541             | (Some t)::tl ->
542                let l1' = (deliftl (j+1) tl) in
543                 try
544                  Some (deliftaux k t)::l1'
545                 with
546                    NotInTheList
547                  | MetaSubstFailure _ ->
548                     to_be_restricted := (i,j)::!to_be_restricted ; None::l1'
549           in
550            let l' = deliftl 1 l1 in
551             C.Meta(i,l')
552      | C.Sort _ as t -> t
553      | C.Implicit _ as t -> t
554      | C.Cast (te,ty) -> C.Cast (deliftaux k te, deliftaux k ty)
555      | C.Prod (n,s,t) -> C.Prod (n, deliftaux k s, deliftaux (k+1) t)
556      | C.Lambda (n,s,t) -> C.Lambda (n, deliftaux k s, deliftaux (k+1) t)
557      | C.LetIn (n,s,t) -> C.LetIn (n, deliftaux k s, deliftaux (k+1) t)
558      | C.Appl l -> C.Appl (List.map (deliftaux k) l)
559      | C.Const (uri,exp_named_subst) ->
560         let exp_named_subst' =
561          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
562         in
563          C.Const (uri,exp_named_subst')
564      | C.MutInd (uri,typeno,exp_named_subst) ->
565         let exp_named_subst' =
566          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
567         in
568          C.MutInd (uri,typeno,exp_named_subst')
569      | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
570         let exp_named_subst' =
571          List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
572         in
573          C.MutConstruct (uri,typeno,consno,exp_named_subst')
574      | C.MutCase (sp,i,outty,t,pl) ->
575         C.MutCase (sp, i, deliftaux k outty, deliftaux k t,
576          List.map (deliftaux k) pl)
577      | C.Fix (i, fl) ->
578         let len = List.length fl in
579         let liftedfl =
580          List.map
581           (fun (name, i, ty, bo) ->
582            (name, i, deliftaux k ty, deliftaux (k+len) bo))
583            fl
584         in
585          C.Fix (i, liftedfl)
586      | C.CoFix (i, fl) ->
587         let len = List.length fl in
588         let liftedfl =
589          List.map
590           (fun (name, ty, bo) -> (name, deliftaux k ty, deliftaux (k+len) bo))
591            fl
592         in
593          C.CoFix (i, liftedfl)
594   in
595    let res =
596     try
597      deliftaux 0 t
598     with
599      NotInTheList ->
600       (* This is the case where we fail even first order unification. *)
601       (* The reason is that our delift function is weaker than first  *)
602       (* order (in the sense of alpha-conversion). See comment above  *)
603       (* related to the delift function.                              *)
604 debug_print "\n!!!!!!!!!!! First Order UnificationFailure, but maybe it could have been successful even in a first order setting (no conversion, only alpha convertibility)! Please, implement a better delift function !!!!!!!!!!!!!!!!" ;
605       raise (Uncertain (sprintf
606         "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables"
607         (ppterm subst t)
608         (String.concat "; "
609           (List.map
610             (function Some t -> ppterm subst t | None -> "_")
611             l))))
612    in
613    let (metasenv, subst) = restrict subst !to_be_restricted metasenv in
614     res, metasenv, subst
615 ;;
616
617 (**** END OF DELIFT ****)
618
619
620 (** {2 Format-like pretty printers} *)
621
622 let fpp_gen ppf s =
623   Format.pp_print_string ppf s;
624   Format.pp_print_newline ppf ();
625   Format.pp_print_flush ppf ()
626
627 let fppsubst ppf subst = fpp_gen ppf (ppsubst subst)
628 let fppterm ppf term = fpp_gen ppf (CicPp.ppterm term)
629 let fppmetasenv ppf metasenv = fpp_gen ppf (ppmetasenv metasenv [])
630