section {* Anti-Unification *} theory Anti_Unification imports Refine_Util begin text {* We implement a simple anti-unification. Currently, we do not handle lambdas, nor sorts, and avoid higher-order variables, i.e., f x and g x will be unified to ?v, not ?v x, and existing higher-order patterns will be collapsed, e.g.: ?f x and ?f x will become ?v. *} ML {* signature ANTI_UNIFICATION = sig type typ_env type term_env type env = typ_env * term_env val empty_typ: typ_env val empty_term: term_env val empty: env val anti_unifyT: typ * typ -> typ_env -> typ * typ_env val anti_unify_env: term * term -> env -> term * env val anti_unify: term * term -> term val anti_unify_list: term list -> term val specialize_tac: Proof.context -> thm list -> tactic' val specialize_net_tac: Proof.context -> (int * thm) Net.net -> tactic' end structure Anti_Unification :ANTI_UNIFICATION = struct structure Term2tab = Table ( type key = term * term val ord = prod_ord Term_Ord.fast_term_ord Term_Ord.fast_term_ord ); structure Typ2tab = Table ( type key = typ * typ val ord = prod_ord Term_Ord.typ_ord Term_Ord.typ_ord ); type typ_env = (typ Typ2tab.table * int) type term_env = (term Term2tab.table * int) type env = typ_env * term_env val empty_typ = (Typ2tab.empty,0) val empty_term = (Term2tab.empty,0) val empty = (empty_typ,empty_term) fun tvar_pair p (vtab,idx) = case Typ2tab.lookup vtab p of NONE => let val tv = TVar (("T",idx),[]) val vtab = Typ2tab.update (p,tv) vtab in (tv,(vtab,idx+1)) end | SOME tv => (tv,(vtab,idx)) fun anti_unifyT (TFree v1, TFree v2) dt = if v1 = v2 then (TFree v1,dt) else tvar_pair (TFree v1, TFree v2) dt | anti_unifyT (p as (Type (n1,l1), Type (n2,l2))) dt = if n1 = n2 andalso (length l1 = length l2) then let val (l,dt) = fold_map anti_unifyT (l1~~l2) dt in (Type (n1,l),dt) end else tvar_pair p dt | anti_unifyT p dt = tvar_pair p dt fun var_pair p (tdt,(vtab,idx)) = case Term2tab.lookup vtab p of NONE => let val (T,tdt) = anti_unifyT (apply2 fastype_of p) tdt val v = Var (("v",idx),T) val vtab = Term2tab.update (p,v) vtab in (v,(tdt,(vtab,idx+1))) end | SOME v => (v,(tdt,(vtab,idx))) fun anti_unify_env (p as (Free (n1,T1), Free (n2,T2))) (tdt,dt) = if n1 = n2 then let val (T,tdt) = anti_unifyT (T1,T2) tdt in (Free (n1,T),(tdt,dt)) end else var_pair p (tdt,dt) | anti_unify_env (p as (Const (n1,T1), Const (n2,T2))) (tdt,dt) = if n1 = n2 then let val (T,tdt) = anti_unifyT (T1,T2) tdt in (Const (n1,T),(tdt,dt)) end else var_pair p (tdt,dt) | anti_unify_env (p as (f1$x1,f2$x2)) dtp = let val (f,dtp) = anti_unify_env (f1,f2) dtp in if is_Var f then var_pair p dtp else let val (x,dtp) = anti_unify_env (x1,x2) dtp in (f$x,dtp) end end | anti_unify_env p dtp = var_pair p dtp fun anti_unify p = anti_unify_env p empty |> #1 fun anti_unify_list l = let fun f [] _ = raise TERM ("anti_unify_list: Empty",[]) | f [t] dt = (t,dt) | f (t1::t2::ts) dt = let val (t,dt) = anti_unify_env (t1,t2) dt in f (t::ts) dt end in f l empty |> #1 end local fun specialize_aux_tac ctxt get_candidates i st = let val maxidx = Thm.maxidx_of st val concl = Logic.concl_of_goal (Thm.prop_of st) i val pre_candidates = get_candidates concl |> map (fn thm => let val tidx = Thm.maxidx_of thm val t = Thm.incr_indexes (maxidx + 1) thm |> Thm.concl_of in (maxidx + tidx + 1,t) end) fun unifies (idx,t) = can (Pattern.unify (Context.Proof ctxt) (t, concl)) (Envir.empty idx) val candidates = filter unifies pre_candidates |> map #2 in case candidates of [] => Seq.single st | _ => let val pattern = anti_unify_list candidates |> Thm.cterm_of ctxt |> Thm.trivial in resolve_tac ctxt [pattern] i st end end in fun specialize_tac ctxt thms = let fun get_candidates concl = filter (fn thm => Term.could_unify (Thm.concl_of thm, concl)) thms in specialize_aux_tac ctxt get_candidates end fun specialize_net_tac ctxt net = let fun get_candidates concl = Net.unify_term net concl |> map #2 in specialize_aux_tac ctxt get_candidates end end end *} end