Theory Higher_Order_Terms.Term_Utils

theory Term_Utils
imports
  "HOL-Library.Finite_Map"
  "HOL-Library.Monad_Syntax"
  "HOL-Library.State_Monad"
begin

fun map2 where
"map2 f (x # xs) (y # ys) = f x y # map2 f xs ys" |
"map2 _ _ _ = []"

lemma map2_elemE:
  assumes "z ∈ set (map2 f xs ys)"
  obtains x y where "x ∈ set xs" "y ∈ set ys" "z = f x y"
using assms by (induct f xs ys rule: map2.induct) auto

lemma map2_elemE1:
  assumes "length xs = length ys" "x ∈ set xs"
  obtains y where "y ∈ set ys" "f x y ∈ set (map2 f xs ys)"
using assms by (induct xs ys rule: list_induct2) auto

lemma map2_elemE2:
  assumes "length xs = length ys" "y ∈ set ys"
  obtains x where "x ∈ set xs" "f x y ∈ set (map2 f xs ys)"
using assms by (induct xs ys rule: list_induct2) auto

lemma map2_cong[fundef_cong]:
  assumes "xs1 = xs2" "ys1 = ys2"
  assumes fg: "⋀x y. x ∈ set xs1 ⟹ y ∈ set ys1 ⟹ f x y = g x y"
  shows "map2 f xs1 ys1 = map2 g xs2 ys2"
proof -
  have "map2 f xs1 ys1 = map2 g xs1 ys1"
    using fg
    by (induction f xs1 ys1 rule: map2.induct) auto
  with assms show ?thesis
    by simp
qed

lemma option_bindE:
  assumes "x ⤜ f = Some a"
  obtains x' where "x = Some x'"  "f x' = Some a"
using assms
by (cases x) auto

lemma rel_option_bind[intro]:
  assumes "rel_option R x y" "⋀a b. R a b ⟹ rel_option R (f a) (g b)"
  shows "rel_option R (x ⤜ f) (y ⤜ g)"
using assms(1) proof (cases rule: option.rel_cases)
  case None
  thus ?thesis
    by simp
next
  case (Some a b)
  thus ?thesis
    using assms(2) by simp
qed

lemma list_split:
  assumes "n < length xs"
  obtains xs1 xs2 where "xs = xs1 @ xs2" "n = length xs2" "0 < length xs1"
proof
  let ?xs1 = "take (length xs - n) xs"
  let ?xs2 = "drop (length xs - n) xs"

  show "xs = ?xs1 @ ?xs2"
    by simp
  show "n = length ?xs2" "0 < length ?xs1"
    using assms by auto
qed

context
  includes fset.lifting
begin

lemma ffUnion_alt_def: "x |∈| ffUnion A ⟷ fBex A (λX. x |∈| X)"
by transfer blast

lemma funion_image_bind_eq: "ffUnion (f |`| M) = fbind M f"
by transfer auto

lemma fbind_funion: "fbind (M |∪| N) f = fbind M f |∪| fbind N f"
by transfer' auto

lemma ffUnion_least: "fBall A (λX. X |⊆| C) ⟹ ffUnion A |⊆| C"
by transfer blast

lemma fbind_iff: "x |∈| fbind S f ⟷ (∃s. x |∈| f s ∧ s |∈| S)"
  by transfer' auto

lemma fBall_pred_weaken: "(⋀x. x |∈| M ⟹ P x ⟹ Q x) ⟹ fBall M P ⟹ fBall M Q"
by auto

end

lemma fmmap_fmupd[simp]:
  "fmmap f (fmupd k v m) = fmupd k (f v) (fmmap f m)"
apply (rule fmap_ext)
by auto

definition fmlookup_default :: "('a, 'b) fmap ⇒ ('a ⇒ 'b) ⇒ 'a ⇒ 'b" where
"fmlookup_default m f x = (case fmlookup m x of None ⇒ f x | Some b ⇒ b)"

end