Theory Env

theory Env
  imports Main "HOL-Library.Library"
begin

section ‹Generic lemmas›

lemma map_of_list_allI:
  assumes "k v. f k = Some v  P (k, v)" and
    "k v. map_of kvs k = Some v  f k = Some v" and
    "distinct (map fst kvs)"
  shows "list_all P kvs"
  using assms(2-)
proof (induction kvs)
  case Nil
  then show ?case by simp
next
  case (Cons kv kvs)
  from Cons.prems(1) have "f (fst kv) = Some (snd kv)"
    by simp
  hence"P kv"
    using assms(1)
    by (cases kv; simp)
  moreover have "list_all P kvs"
    using Cons.IH Cons.prems
    by (metis Some_eq_map_of_iff distinct.simps(2) list.set_intros(2) list.simps(9))
  ultimately show ?case by simp
qed

section ‹Environment›

locale env =
  fixes
    empty :: 'env and
    get :: "'env  'key  'val option" and
    add :: "'env  'key  'val  'env" and
    to_list :: "'env  ('key × 'val) list"
  assumes
    get_empty: "get empty x = None" and
    get_add_eq: "get (add e x v) x = Some v" and
    get_add_neq: "x  y  get (add e x v) y = get e y" and
    to_list_correct: "map_of (to_list e) = get e" and
    to_list_distinct: "distinct (map fst (to_list e))"

begin

declare get_empty[simp]
declare get_add_eq[simp]
declare get_add_neq[simp]

definition singleton where
  "singleton  add empty"

fun add_list :: "'env  ('key × 'val) list  'env" where
  "add_list e [] = e" |
  "add_list e (x # xs) = add (add_list e xs) (fst x) (snd x)"

definition from_list :: "('key × 'val) list  'env" where
  "from_list  add_list empty"

lemma from_list_correct: "get (from_list xs) = map_of xs"
proof (induction xs)
  case Nil
  then show ?case
    using get_empty by (simp add: from_list_def)
next
  case (Cons x xs)
  show ?case
    using get_add_eq get_add_neq Cons.IH by (auto simp: from_list_def)
qed

lemma from_list_Nil[simp]: "from_list [] = empty"
  by (simp add: from_list_def)

lemma get_from_list_to_list: "get (from_list (to_list e)) = get e"
proof
  fix x
  show "get (from_list (to_list e)) x = get e x"
    unfolding from_list_correct
    unfolding to_list_correct
    by (rule refl)
qed

lemma to_list_list_allI:
  assumes "k v. get e k = Some v  P (k, v)"
  shows "list_all P (to_list e)"
proof (rule map_of_list_allI[of "get e"])
  fix k v
  show "get e k = Some v  P (k, v)"
    using assms by simp
next
  fix k v
  show "map_of (to_list e) k = Some v  get e k = Some v"
    unfolding to_list_correct by assumption
next
  show "distinct (map fst (to_list e))"
    by (rule to_list_distinct)
qed

definition map_entry where
  "map_entry e k f  case get e k of None  e | Some v  add e k (f v)"

lemma get_map_entry_eq[simp]: "get (map_entry e k f) k = map_option f (get e k)"
  unfolding map_entry_def
  by (cases "get e k") simp_all

lemma get_map_entry_neq[simp]: "x  y  get (map_entry e x f) y = get e y"
  unfolding map_entry_def
  by (cases "get e x") simp_all

lemma dom_map_entry[simp]: "dom (get (map_entry e k f)) = dom (get e)"
  unfolding dom_def
  apply (rule Collect_cong)
  by (metis None_eq_map_option_iff get_map_entry_eq get_map_entry_neq)

lemma get_map_entry_conv:
  "get (map_entry e x f) y = map_option (λv. if x = y then f v else  v) (get e y)"
  unfolding map_entry_def
  by (cases "get e x"; cases "x = y"; simp add: option.map_ident)

lemma map_option_comp_map_entry:
  assumes "x  ran (get e). f (g x) = f x"
  shows "map_option f  get (map_entry e k g) = map_option f  get e"
proof (intro ext)
  fix x
  show "(map_option f  get (map_entry e k g)) x = (map_option f  get e) x"
  proof (cases "k = x")
    case True
    thus ?thesis
      using assms(1)
      by (auto simp: get_map_entry_eq option.map_comp intro!: map_option_cong ranI)
  next
    case False
    then show ?thesis
      by (simp add: get_map_entry_neq)
  qed
qed

lemma map_option_comp_get_add:
  assumes "k  dom (get e)" and "x  ran (get e). f v = f x"
  shows "map_option f  get (add e k v) = map_option f  get e"
proof (intro ext)
  fix x
  show "(map_option f  get (add e k v)) x = (map_option f  get e) x"
  proof (cases "x = k")
    case True
    show ?thesis
    proof (cases "get e x")
      case None
      thus ?thesis
        using True assms(1) by auto
    next
      case (Some v')
      thus ?thesis
        using True assms(2) by (auto intro: ranI)
    qed
  next
    case False
    thus ?thesis by simp
  qed
qed

end

end