Theory Unification_Compat

chapter ‹Instantiation for HOL-ex.Unification› from session HOL-ex›

theory Unification_Compat
imports
  "HOL-ex.Unification"
  Term_Class
begin

text ‹
  The Isabelle library provides a unification algorithm on lambda-free terms. To illustrate
  flexibility of the term algebra, I instantiate my class with that term type. The major issue is
  that those terms are parameterized over the constant and variable type, which cannot easily be
  supported by the classy approach, where those types are fixed to @{typ name}. As a workaround, I
  introduce a class that requires the constant and variable type to be isomorphic to @{typ name}.
›

hide_const (open) Unification.subst

class is_name =
  fixes of_name :: "name  'a"
  assumes bij: "bij of_name"
begin

definition to_name :: "'a  name" where
"to_name = inv of_name"

lemma to_of_name[simp]: "to_name (of_name a) = a"
unfolding to_name_def using bij by (metis bij_inv_eq_iff)

lemma of_to_name[simp]: "of_name (to_name a) = a"
unfolding to_name_def using bij by (meson bij_inv_eq_iff)

lemma of_name_inj: "of_name name1 = of_name name2  name1 = name2"
using bij by (metis to_of_name)

end

instantiation name :: is_name begin

definition of_name_name :: "name  name" where
[code_unfold]: "of_name_name x = x"

instance by standard (auto simp: of_name_name_def bij_betw_def inj_on_def)

end

lemma [simp, code_unfold]: "(to_name :: name  name) = id"
unfolding to_name_def of_name_name_def by auto

instantiation trm :: (is_name) "pre_term" begin

definition app_trm where
"app_trm = Comb"

definition unapp_trm where
"unapp_trm t = (case t of Comb t u  Some (t, u) | _  None)"

definition const_trm where
"const_trm n = trm.Const (of_name n)"

definition unconst_trm where
"unconst_trm t = (case t of trm.Const a  Some (to_name a) | _  None)"

definition free_trm where
"free_trm n = Var (of_name n)"

definition unfree_trm where
"unfree_trm t = (case t of Var a  Some (to_name a) | _  None)"

primrec consts_trm :: "'a trm  name fset" where
"consts_trm (Var _) = {||}" |
"consts_trm (trm.Const c) = {| to_name c |}" |
"consts_trm (M  N) = consts_trm M |∪| consts_trm N"

context
  includes fset.lifting
begin

lift_definition frees_trm :: "'a trm  name fset" is "λt. to_name ` vars_of t"
  by auto

end

lemma frees_trm[code, simp]:
  "frees (Var v) = {| to_name v |}"
  "frees (trm.Const c) = {||}"
  "frees (M  N) = frees M |∪| frees N"
including fset.lifting
by (transfer; auto)+

primrec subst_trm :: "'a trm  (name, 'a trm) fmap  'a trm" where
"subst_trm (Var v) env = (case fmlookup env (to_name v) of Some v'  v' | _  Var v)" |
"subst_trm (trm.Const c) _ = trm.Const c" |
"subst_trm (M  N) env = subst_trm M env  subst_trm N env"

instance
by standard
   (auto
      simp: app_trm_def unapp_trm_def const_trm_def unconst_trm_def free_trm_def unfree_trm_def of_name_inj
      split: trm.splits option.splits)

end

instantiation trm :: (is_name) "term" begin

definition abs_pred_trm :: "('a trm  bool)  'a trm  bool" where
"abs_pred_trm P t  True"

instance proof (standard, goal_cases)
  case (1 P t)
  then show ?case
    proof (induction t)
      case Var
      then show ?case
        unfolding free_trm_def
        by (metis of_to_name)
    next
      case Const
      then show ?case
        unfolding const_trm_def
        by (metis of_to_name)
    qed (auto simp: app_trm_def)
qed (auto simp: abs_pred_trm_def)

end

lemma assoc_alt_def[simp]:
  "assoc x y t = (case map_of t x of Some y'  y' | _  y)"
by (induction t) auto

lemma subst_eq: "Unification.subst t s = subst t (fmap_of_list s)"
by (induction t) (auto split: option.splits simp: fmlookup_of_list)

end