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