+
+let proof = ref (None : (metas_context * Cic.term * Cic.term) option);;
+(*CSC: Quando facciamo Clear di una ipotesi, cosa succede? *)
+(* Note: the sequent is redundant: it can be computed from the type of the *)
+(* metavariable and its context in the proof. We keep it just for efficiency *)
+(* because computing the context of a term may be quite expensive. *)
+let goal = ref (None : (int * sequent) option);;
+
+exception NotImplemented
+
+(*CSC: Funzione che deve sparire!!! *)
+let cic_context_of_context =
+ List.map
+ (function
+ Declaration,_,t -> t
+ | Definition,_,_ -> raise NotImplemented
+ )
+;;
+
+let refine_meta meta term newmetasenv =
+ let (metasenv,bo,ty) =
+ match !proof with
+ None -> assert false
+ | Some (metasenv,bo,ty) -> metasenv,bo,ty
+ in
+ let metasenv' = newmetasenv @ (List.remove_assoc meta metasenv) in
+ let bo' =
+ let rec aux =
+ let module C = Cic in
+ function
+ C.Rel _ as t -> t
+ | C.Var _ as t -> t
+ | C.Meta meta' when meta=meta' -> term
+ | C.Meta _ as t -> t
+ | C.Sort _ as t -> t
+ | C.Implicit as t -> t
+ | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
+ | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
+ | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
+ | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
+ | C.Appl l -> C.Appl (List.map aux l)
+ | C.Const _ as t -> t
+ | C.Abst _ as t -> t
+ | C.MutInd _ as t -> t
+ | C.MutConstruct _ as t -> t
+ | C.MutCase (sp,cookingsno,i,outt,t,pl) ->
+ C.MutCase (sp,cookingsno,i,aux outt, aux t,
+ List.map aux pl)
+ | C.Fix (i,fl) ->
+ let substitutedfl =
+ List.map
+ (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
+ fl
+ in
+ C.Fix (i, substitutedfl)
+ | C.CoFix (i,fl) ->
+ let substitutedfl =
+ List.map
+ (fun (name,ty,bo) -> (name, aux ty, aux bo))
+ fl
+ in
+ C.CoFix (i, substitutedfl)
+ in
+ aux bo
+ in
+ proof := Some (metasenv',bo',ty)
+;;
+
+let new_meta () =
+ let metasenv =
+ match !proof with
+ None -> assert false
+ | Some (metasenv,_,_) -> metasenv
+ in
+ let rec aux =
+ function
+ None,[] -> 1
+ | Some n,[] -> n
+ | None,(n,_)::tl -> aux (Some n,tl)
+ | Some m,(n,_)::tl -> if n > m then aux (Some n,tl) else aux (Some m,tl)
+ in
+ 1 + aux (None,metasenv)
+;;
+
+(* metas_in_term term *)
+(* Returns the ordered list of the metas that occur in [term]. *)
+(* Duplicates are removed. The implementation is not very efficient. *)
+let metas_in_term term =
+ let module C = Cic in
+ let rec aux =
+ function
+ C.Rel _
+ | C.Var _ -> []
+ | C.Meta n -> [n]
+ | C.Sort _
+ | C.Implicit -> []
+ | C.Cast (te,ty) -> (aux te) @ (aux ty)
+ | C.Prod (_,s,t) -> (aux s) @ (aux t)
+ | C.Lambda (_,s,t) -> (aux s) @ (aux t)
+ | C.LetIn (_,s,t) -> (aux s) @ (aux t)
+ | C.Appl l -> List.fold_left (fun i t -> i @ (aux t)) [] l
+ | C.Const _
+ | C.Abst _
+ | C.MutInd _
+ | C.MutConstruct _ -> []
+ | C.MutCase (sp,cookingsno,i,outt,t,pl) ->
+ (aux outt) @ (aux t) @
+ (List.fold_left (fun i t -> i @ (aux t)) [] pl)
+ | C.Fix (i,fl) ->
+ List.fold_left (fun i (_,_,ty,bo) -> i @ (aux bo) @ (aux ty)) [] fl
+ | C.CoFix (i,fl) ->
+ List.fold_left (fun i (_,ty,bo) -> i @ (aux bo) @ (aux ty)) [] fl
+ in
+ let metas = aux term in
+ let rec elim_duplicates =
+ function
+ [] -> []
+ | he::tl ->
+ he::(elim_duplicates (List.filter (function el -> he <> el) tl))
+ in
+ elim_duplicates metas
+;;
+
+(* perforate context term ty *)
+(* replaces the term [term] in the proof with a new metavariable whose type *)
+(* is [ty]. [context] must be the context of [term] in the whole proof. This *)
+(* could be easily computed; so the only reasons to have it as an argument *)
+(* are efficiency reasons. *)
+let perforate context term ty =
+ let module C = Cic in
+ let newmeta = new_meta () in
+ match !proof with
+ None -> assert false
+ | Some (metasenv,bo,gty) ->
+ (* We push the new meta at the end of the list for pretty-printing *)
+ (* purposes: in this way metas are ordered. *)
+ let metasenv' = metasenv@[newmeta,ty] in
+ let rec aux =
+ function
+ (* Is == strong enough? *)
+ t when t == term -> C.Meta newmeta
+ | C.Rel _ as t -> t
+ | C.Var _ as t -> t
+ | C.Meta _ as t -> t
+ | C.Sort _ as t -> t
+ | C.Implicit as t -> t
+ | C.Cast (te,ty) -> C.Cast (aux te, aux ty)
+ | C.Prod (n,s,t) -> C.Prod (n, aux s, aux t)
+ | C.Lambda (n,s,t) -> C.Lambda (n, aux s, aux t)
+ | C.LetIn (n,s,t) -> C.LetIn (n, aux s, aux t)
+ | C.Appl l -> C.Appl (List.map aux l)
+ | C.Const _ as t -> t
+ | C.Abst _ as t -> t
+ | C.MutInd _ as t -> t
+ | C.MutConstruct _ as t -> t
+ | C.MutCase (sp,cookingsno,i,outt,t,pl) ->
+ C.MutCase (sp,cookingsno,i,aux outt, aux t,
+ List.map aux pl)
+ | C.Fix (i,fl) ->
+ let substitutedfl =
+ List.map
+ (fun (name,i,ty,bo) -> (name, i, aux ty, aux bo))
+ fl
+ in
+ C.Fix (i, substitutedfl)
+ | C.CoFix (i,fl) ->
+ let substitutedfl =
+ List.map
+ (fun (name,ty,bo) -> (name, aux ty, aux bo))
+ fl
+ in
+ C.CoFix (i, substitutedfl)
+ in
+ let bo' = aux bo in
+ (* It may be possible that some metavariables occurred only in *)
+ (* the term we are perforating and they now occurs no more. We *)
+ (* get rid of them, collecting the really useful metavariables *)
+ (* in metasenv''. *)
+ let newmetas = metas_in_term bo' in
+ let metasenv'' =
+ List.filter (function (n,_) -> List.mem n newmetas) metasenv'
+ in
+ proof := Some (metasenv'',bo',gty) ;
+ goal := Some (newmeta,(context,ty)) ;
+ newmeta
+;;
+
+(************************************************************)
+(* Some easy tactics. *)
+(************************************************************)
+
+exception Fail of string;;
+
+let intros () =
+ let module C = Cic in
+ let module R = CicReduction in
+ let metasenv =
+ match !proof with
+ None -> assert false
+ | Some (metasenv,_,_) -> metasenv
+ in
+ let (metano,context,ty) =
+ match !goal with
+ None -> assert false
+ | Some (metano,(context,ty)) -> metano,context,ty
+ in
+ let newmeta = new_meta () in
+ let rec collect_context =
+ function
+ C.Cast (te,_) -> collect_context te
+ | C.Prod (n,s,t) ->
+ let (ctx,ty,bo) = collect_context t in
+ ((Declaration,n,s)::ctx,ty,C.Lambda(n,s,bo))
+ | C.LetIn (n,s,t) ->
+ let (ctx,ty,bo) = collect_context t in
+ ((Definition,n,s)::ctx,ty,C.LetIn(n,s,bo))
+ | _ as t -> [], t, (C.Meta newmeta)
+ in
+ let revcontext',ty',bo' = collect_context ty in
+ let context'' = (List.rev revcontext') @ context in
+ refine_meta metano bo' [newmeta,ty'] ;
+ goal := Some (newmeta,(context'',ty'))
+;;
+
+(* The term bo must be closed in the current context *)
+let exact bo =
+ let module T = CicTypeChecker in
+ let module R = CicReduction in
+ let metasenv =
+ match !proof with
+ None -> assert false
+ | Some (metasenv,_,_) -> metasenv
+ in
+ let (metano,context,ty) =
+ match !goal with
+ None -> assert false
+ | Some (metano,(context,ty)) ->
+ assert (ty = List.assoc metano metasenv) ;
+ (* Invariant: context is the actual context of the meta in the proof *)
+ metano,context,ty
+ in
+ (*CSC: deve sparire! *)
+ let context = cic_context_of_context context in
+ if R.are_convertible (T.type_of_aux' metasenv context bo) ty then
+ refine_meta metano bo []
+ else
+ raise (Fail "The type of the provided term is not the one expected.")
+;;