4 exception AssertFailure of string
5 exception MetaSubstFailure of string
7 let debug_print = prerr_endline
9 type substitution = (int * Cic.term) list
11 (*** Functions to apply a substitution ***)
13 let apply_subst_gen ~appl_fun subst term =
16 let module S = CicSubstitution in
22 let t = List.assoc i subst in
23 um_aux (S.lift_meta l t)
24 with Not_found -> (* not constrained variable, i.e. free in subst*)
26 List.map (function None -> None | Some t -> Some (um_aux t)) l
30 | C.Implicit _ -> assert false
31 | C.Cast (te,ty) -> C.Cast (um_aux te, um_aux ty)
32 | C.Prod (n,s,t) -> C.Prod (n, um_aux s, um_aux t)
33 | C.Lambda (n,s,t) -> C.Lambda (n, um_aux s, um_aux t)
34 | C.LetIn (n,s,t) -> C.LetIn (n, um_aux s, um_aux t)
35 | C.Appl (hd :: tl) -> appl_fun um_aux hd tl
36 | C.Appl _ -> assert false
37 | C.Const (uri,exp_named_subst) ->
38 let exp_named_subst' =
39 List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
41 C.Const (uri, exp_named_subst')
42 | C.MutInd (uri,typeno,exp_named_subst) ->
43 let exp_named_subst' =
44 List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
46 C.MutInd (uri,typeno,exp_named_subst')
47 | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
48 let exp_named_subst' =
49 List.map (fun (uri, t) -> (uri, um_aux t)) exp_named_subst
51 C.MutConstruct (uri,typeno,consno,exp_named_subst')
52 | C.MutCase (sp,i,outty,t,pl) ->
53 let pl' = List.map um_aux pl in
54 C.MutCase (sp, i, um_aux outty, um_aux t, pl')
57 List.map (fun (name, i, ty, bo) -> (name, i, um_aux ty, um_aux bo)) fl
62 List.map (fun (name, ty, bo) -> (name, um_aux ty, um_aux bo)) fl
70 let appl_fun um_aux he tl =
71 let tl' = List.map um_aux tl in
74 Cic.Appl l -> Cic.Appl (l@tl')
75 | he' -> Cic.Appl (he'::tl')
78 apply_subst_gen ~appl_fun
81 (* apply_subst_reducing subst (Some (mtr,reductions_no)) t *)
82 (* performs as (apply_subst subst t) until it finds an application of *)
83 (* (META [meta_to_reduce]) that, once unwinding is performed, creates *)
84 (* a new beta-redex; in this case up to [reductions_no] consecutive *)
85 (* beta-reductions are performed. *)
86 (* Hint: this function is usually called when [reductions_no] *)
87 (* eta-expansions have been performed and the head of the new *)
88 (* application has been unified with (META [meta_to_reduce]): *)
89 (* during the unwinding the eta-expansions are undone. *)
91 let apply_subst_reducing meta_to_reduce =
92 let appl_fun um_aux he tl =
93 let tl' = List.map um_aux tl in
96 Cic.Appl l -> Cic.Appl (l@tl')
97 | he' -> Cic.Appl (he'::tl')
100 match meta_to_reduce, he with
101 Some (mtr,reductions_no), Cic.Meta (m,_) when m = mtr ->
102 let rec beta_reduce =
104 (n,(Cic.Appl (Cic.Lambda (_,_,t)::he'::tl'))) when n > 0 ->
105 let he'' = CicSubstitution.subst he' t in
109 beta_reduce (n-1,Cic.Appl(he''::tl'))
112 beta_reduce (reductions_no,t')
116 apply_subst_gen ~appl_fun
118 let rec apply_subst_context subst context =
122 | Some (n, Cic.Decl t) ->
123 let t' = apply_subst subst t in
124 Some (n, Cic.Decl t') :: context
125 | Some (n, Cic.Def (t, ty)) ->
129 | Some ty -> Some (apply_subst subst ty)
131 let t' = apply_subst subst t in
132 Some (n, Cic.Def (t', ty')) :: context
133 | None -> None :: context)
136 let apply_subst_metasenv subst metasenv =
138 (fun (n, context, ty) ->
139 (n, apply_subst_context subst context, apply_subst subst ty))
141 (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
144 (***** Pretty printing functions ******)
149 (fun (idx, term) -> Printf.sprintf "?%d := %s" idx (CicPp.ppterm term))
153 let ppterm subst term = CicPp.ppterm (apply_subst subst term)
155 let ppterm_in_context subst term name_context =
156 CicPp.pp (apply_subst subst term) name_context
158 let ppcontext' ?(sep = "\n") subst context =
159 let separate s = if s = "" then "" else s ^ sep in
161 (fun context_entry (i,name_context) ->
162 match context_entry with
163 Some (n,Cic.Decl t) ->
164 sprintf "%s%s : %s" (separate i) (CicPp.ppname n)
165 (ppterm_in_context subst t name_context), (Some n)::name_context
166 | Some (n,Cic.Def (bo,ty)) ->
167 sprintf "%s%s : %s := %s" (separate i) (CicPp.ppname n)
170 | Some ty -> ppterm_in_context subst ty name_context)
171 (ppterm_in_context subst bo name_context), (Some n)::name_context
173 sprintf "%s_ :? _" (separate i), None::name_context
176 let ppcontext ?sep subst context = fst (ppcontext' ?sep subst context)
178 let ppmetasenv ?(sep = "\n") metasenv subst =
182 let context,name_context = ppcontext' ~sep:"; " subst c in
183 sprintf "%s |- ?%d: %s" context i
184 (ppterm_in_context subst t name_context))
186 (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
189 (* From now on we recreate a kernel abstraction where substitutions are part of
192 let lift subst n term =
193 let term = apply_subst subst term in
195 CicSubstitution.lift n term
197 raise (MetaSubstFailure ("Lift failure: " ^ Printexc.to_string e))
199 let subst subst t1 t2 =
200 let t1 = apply_subst subst t1 in
201 let t2 = apply_subst subst t2 in
203 CicSubstitution.subst t1 t2
205 raise (MetaSubstFailure ("Subst failure: " ^ Printexc.to_string e))
207 let whd subst context term =
208 let term = apply_subst subst term in
209 let context = apply_subst_context subst context in
211 CicReduction.whd context term
213 raise (MetaSubstFailure ("Weak head reduction failure: " ^
214 Printexc.to_string e))
216 let are_convertible subst context t1 t2 =
217 let context = apply_subst_context subst context in
218 let t1 = apply_subst subst t1 in
219 let t2 = apply_subst subst t2 in
220 CicReduction.are_convertible context t1 t2
222 let tempi_type_of_aux_subst = ref 0.0;;
223 let tempi_type_of_aux = ref 0.0;;
225 let type_of_aux' metasenv subst context term =
226 let time1 = Unix.gettimeofday () in
227 let term = apply_subst subst term in
228 let context = apply_subst_context subst context in
231 (fun (i, c, t) -> (i, apply_subst_context subst c, apply_subst subst t))
233 (fun (i, _, _) -> not (List.exists (fun (j, _) -> (j = i)) subst))
236 let time2 = Unix.gettimeofday () in
239 CicTypeChecker.type_of_aux' metasenv context term
240 with CicTypeChecker.TypeCheckerFailure msg ->
241 raise (MetaSubstFailure ("Type checker failure: " ^ msg))
243 let time3 = Unix.gettimeofday () in
244 tempi_type_of_aux_subst := !tempi_type_of_aux_subst +. time3 -. time1 ;
245 tempi_type_of_aux := !tempi_type_of_aux +. time2 -. time1 ;
249 (* the delift function takes in input a metavariable index, an ordered list of
250 * optional terms [t1,...,tn] and a term t, and substitutes every tk = Some
251 * (rel(nk)) with rel(k). Typically, the list of optional terms is the explicit
252 * substitution that is applied to a metavariable occurrence and the result of
253 * the delift function is a term the implicit variable can be substituted with
254 * to make the term [t] unifiable with the metavariable occurrence. In general,
255 * the problem is undecidable if we consider equivalence in place of alpha
256 * convertibility. Our implementation, though, is even weaker than alpha
257 * convertibility, since it replace the term [tk] if and only if [tk] is a Rel
258 * (missing all the other cases). Does this matter in practice?
259 * The metavariable index is the index of the metavariable that must not occur
260 * in the term (for occur check).
263 exception NotInTheList;;
268 [] -> raise NotInTheList
269 | (Some (Cic.Rel m))::_ when m=n -> k
270 | _::tl -> aux (k+1) tl in
276 let rec force_does_not_occur subst to_be_restricted t =
277 let module C = Cic in
278 let more_to_be_restricted = ref [] in
279 let rec aux k = function
280 C.Rel r when List.mem (r - k) to_be_restricted -> raise Occur
283 | C.Implicit _ -> assert false
285 (* we do not retrieve the term associated to ?n in subst since *)
286 (* in this way we can restrict if something goes wrong *)
298 more_to_be_restricted := (n,!i) :: !more_to_be_restricted;
303 | C.Cast (te,ty) -> C.Cast (aux k te, aux k ty)
304 | C.Prod (name,so,dest) -> C.Prod (name, aux k so, aux (k+1) dest)
305 | C.Lambda (name,so,dest) -> C.Lambda (name, aux k so, aux (k+1) dest)
306 | C.LetIn (name,so,dest) -> C.LetIn (name, aux k so, aux (k+1) dest)
307 | C.Appl l -> C.Appl (List.map (aux k) l)
308 | C.Var (uri,exp_named_subst) ->
309 let exp_named_subst' =
310 List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
312 C.Var (uri, exp_named_subst')
313 | C.Const (uri, exp_named_subst) ->
314 let exp_named_subst' =
315 List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
317 C.Const (uri, exp_named_subst')
318 | C.MutInd (uri,tyno,exp_named_subst) ->
319 let exp_named_subst' =
320 List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
322 C.MutInd (uri, tyno, exp_named_subst')
323 | C.MutConstruct (uri,tyno,consno,exp_named_subst) ->
324 let exp_named_subst' =
325 List.map (fun (uri,t) -> (uri, aux k t)) exp_named_subst
327 C.MutConstruct (uri, tyno, consno, exp_named_subst')
328 | C.MutCase (uri,tyno,out,te,pl) ->
329 C.MutCase (uri, tyno, aux k out, aux k te, List.map (aux k) pl)
331 let len = List.length fl in
332 let k_plus_len = k + len in
335 (fun (name,j,ty,bo) -> (name, j, aux k ty, aux k_plus_len bo)) fl
339 let len = List.length fl in
340 let k_plus_len = k + len in
343 (fun (name,ty,bo) -> (name, aux k ty, aux k_plus_len bo)) fl
348 (!more_to_be_restricted, res)
350 let rec restrict subst to_be_restricted metasenv =
351 let names_of_context_indexes context indexes =
356 match List.nth context i with
357 | None -> assert false
358 | Some (n, _) -> CicPp.ppname n
360 Failure _ -> assert false
363 let force_does_not_occur_in_context to_be_restricted = function
365 | Some (name, Cic.Decl t) ->
366 let (more_to_be_restricted, t') =
367 force_does_not_occur subst to_be_restricted t
369 more_to_be_restricted, Some (name, Cic.Decl t')
370 | Some (name, Cic.Def (bo, ty)) ->
371 let (more_to_be_restricted, bo') =
372 force_does_not_occur subst to_be_restricted bo
374 let more_to_be_restricted, ty' =
376 | None -> more_to_be_restricted, None
378 let more_to_be_restricted', ty' =
379 force_does_not_occur subst to_be_restricted ty
381 more_to_be_restricted @ more_to_be_restricted',
384 more_to_be_restricted, Some (name, Cic.Def (bo', ty'))
386 let rec erase i to_be_restricted n = function
387 | [] -> [], to_be_restricted, []
389 let more_to_be_restricted,restricted,tl' =
390 erase (i+1) to_be_restricted n tl
392 let restrict_me = List.mem i restricted in
394 more_to_be_restricted, restricted, None:: tl'
397 let more_to_be_restricted', hd' =
398 let delifted_restricted =
402 | j::tl when j > i -> (j - i)::aux tl
407 force_does_not_occur_in_context delifted_restricted hd
409 more_to_be_restricted @ more_to_be_restricted',
410 restricted, hd' :: tl'
412 more_to_be_restricted, (i :: restricted), None :: tl')
414 let (more_to_be_restricted, metasenv, subst) =
416 (fun (n, context, t) (more, metasenv, subst) ->
417 let to_be_restricted =
418 List.map snd (List.filter (fun (m, _) -> m = n) to_be_restricted)
420 let (more_to_be_restricted, restricted, context') =
421 (* just an optimization *)
422 if to_be_restricted = [] then
425 erase 1 to_be_restricted n context
428 let more_to_be_restricted', t' =
429 force_does_not_occur subst restricted t
431 let metasenv' = (n, context', t') :: metasenv in
433 let s = List.assoc n subst in
435 let more_to_be_restricted'', s' =
436 force_does_not_occur subst restricted s
438 let subst' = (n, s') :: (List.remove_assoc n subst) in
440 more @ more_to_be_restricted @ more_to_be_restricted' @
441 more_to_be_restricted''
443 (more, metasenv', subst')
445 raise (MetaSubstFailure (sprintf
446 "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"
447 n (names_of_context_indexes context to_be_restricted) n
449 with Not_found -> (more @ more_to_be_restricted @ more_to_be_restricted', metasenv', subst))
451 raise (MetaSubstFailure (sprintf
452 "Cannot restrict the context of the metavariable ?%d over the hypotheses %s since metavariable's type depends on at least one of them"
453 n (names_of_context_indexes context to_be_restricted))))
454 metasenv ([], [], subst)
456 match more_to_be_restricted with
457 | [] -> (metasenv, subst)
458 | _ -> restrict subst more_to_be_restricted metasenv
461 (*CSC: maybe we should rename delift in abstract, as I did in my dissertation *)
462 let delift n subst context metasenv l t =
463 let module S = CicSubstitution in
465 let (_, canonical_context, _) = CicUtil.lookup_meta n metasenv in
466 List.map2 (fun ct lt ->
472 let to_be_restricted = ref [] in
473 let rec deliftaux k =
474 let module C = Cic in
478 C.Rel m (*CSC: che succede se c'e' un Def? Dovrebbe averlo gia' *)
479 (*CSC: deliftato la regola per il LetIn *)
480 (*CSC: FALSO! La regola per il LetIn non lo fa *)
482 (match List.nth context (m-k-1) with
483 Some (_,C.Def (t,_)) ->
484 (*CSC: Hmmm. This bit of reduction is not in the spirit of *)
485 (*CSC: first order unification. Does it help or does it harm? *)
486 deliftaux k (S.lift m t)
487 | Some (_,C.Decl t) ->
488 C.Rel ((position (m-k) l) + k)
489 | None -> raise (MetaSubstFailure "RelToHiddenHypothesis"))
490 | C.Var (uri,exp_named_subst) ->
491 let exp_named_subst' =
492 List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
494 C.Var (uri,exp_named_subst')
495 | C.Meta (i, l1) as t ->
497 raise (MetaSubstFailure (sprintf
498 "Cannot unify the metavariable ?%d with a term that has as subterm %s in which the same metavariable occurs (occur check)"
501 (* I do not consider the term associated to ?i in subst since *)
502 (* in this way I can restrict if something goes wrong. *)
506 | None::tl -> None::(deliftl (j+1) tl)
508 let l1' = (deliftl (j+1) tl) in
510 Some (deliftaux k t)::l1'
513 | MetaSubstFailure _ ->
514 to_be_restricted := (i,j)::!to_be_restricted ; None::l1'
516 let l' = deliftl 1 l1 in
519 | C.Implicit _ as t -> t
520 | C.Cast (te,ty) -> C.Cast (deliftaux k te, deliftaux k ty)
521 | C.Prod (n,s,t) -> C.Prod (n, deliftaux k s, deliftaux (k+1) t)
522 | C.Lambda (n,s,t) -> C.Lambda (n, deliftaux k s, deliftaux (k+1) t)
523 | C.LetIn (n,s,t) -> C.LetIn (n, deliftaux k s, deliftaux (k+1) t)
524 | C.Appl l -> C.Appl (List.map (deliftaux k) l)
525 | C.Const (uri,exp_named_subst) ->
526 let exp_named_subst' =
527 List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
529 C.Const (uri,exp_named_subst')
530 | C.MutInd (uri,typeno,exp_named_subst) ->
531 let exp_named_subst' =
532 List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
534 C.MutInd (uri,typeno,exp_named_subst')
535 | C.MutConstruct (uri,typeno,consno,exp_named_subst) ->
536 let exp_named_subst' =
537 List.map (function (uri,t) -> uri,deliftaux k t) exp_named_subst
539 C.MutConstruct (uri,typeno,consno,exp_named_subst')
540 | C.MutCase (sp,i,outty,t,pl) ->
541 C.MutCase (sp, i, deliftaux k outty, deliftaux k t,
542 List.map (deliftaux k) pl)
544 let len = List.length fl in
547 (fun (name, i, ty, bo) ->
548 (name, i, deliftaux k ty, deliftaux (k+len) bo))
553 let len = List.length fl in
556 (fun (name, ty, bo) -> (name, deliftaux k ty, deliftaux (k+len) bo))
559 C.CoFix (i, liftedfl)
566 (* This is the case where we fail even first order unification. *)
567 (* The reason is that our delift function is weaker than first *)
568 (* order (in the sense of alpha-conversion). See comment above *)
569 (* related to the delift function. *)
570 debug_print "!!!!!!!!!!! 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 !!!!!!!!!!!!!!!!" ;
571 raise (MetaSubstFailure (sprintf
572 "Error trying to abstract %s over [%s]: the algorithm only tried to abstract over bound variables"
576 (function Some t -> ppterm subst t | None -> "_")
579 let (metasenv, subst) = restrict subst !to_be_restricted metasenv in
583 (**** END OF DELIFT ****)
586 (** {2 Format-like pretty printers} *)
589 Format.pp_print_string ppf s;
590 Format.pp_print_newline ppf ();
591 Format.pp_print_flush ppf ()
593 let fppsubst ppf subst = fpp_gen ppf (ppsubst subst)
594 let fppterm ppf term = fpp_gen ppf (CicPp.ppterm term)
595 let fppmetasenv ppf metasenv = fpp_gen ppf (ppmetasenv metasenv [])