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