Theory GHC_Rewrite_Rules

section ‹GHC's "fold/build" Rule›

theory GHC_Rewrite_Rules
  imports "../HOLCF_Prelude"
begin

subsection ‹Approximating the Rewrite Rule›

text ‹
  The original rule looks as follows (see also cite"ghc-rewriting"):
  \begin{verbatim}
  "fold/build"
    forall k z (g :: forall b. (a -> b -> b) -> b -> b).
    foldr k z (build g) = g k z
  \end{verbatim}
  Since we do not have rank-2 polymorphic types in Isabelle/HOL, we try to imitate a similar
  statement by introducing a new type that combines possible folds with their argument lists, i.e.,
  @{term f} below is a function that, in a way, represents the list @{term xs}, but where list
  constructors are functionally abstracted.
›

abbreviation (input) abstract_list where
  "abstract_list xs  (Λ c n. foldrcnxs)"

cpodef ('a, 'b) listfun =
  "{(f :: ('a  'b  'b)  'b  'b, xs). f = abstract_list xs}"
  by auto

definition listfun :: "('a, 'b) listfun  ('a  'b  'b)  'b  'b" where
  "listfun = (Λ g. Product_Type.fst (Rep_listfun g))"

definition build :: "('a, 'b) listfun  ['a]" where
  "build = (Λ g. Product_Type.snd (Rep_listfun g))"

definition augment :: "('a, 'b) listfun  ['a]  ['a]" where
  "augment = (Λ g xs. buildg ++ xs)"

definition listfun_comp :: "('a, 'b) listfun  ('a, 'b) listfun  ('a, 'b) listfun" where
  "listfun_comp = (Λ g h.
    Abs_listfun (Λ c n. listfungc(listfunhcn), buildg ++ buildh))"

abbreviation
  listfun_comp_infix :: "('a, 'b) listfun  ('a, 'b) listfun  ('a, 'b) listfun" (infixl ∘lf 55)
  where
    "g ∘lf h  listfun_compgh"

fixrec mapFB :: "('b  'c  'c)  ('a  'b)  'a  'c  'c" where
  "mapFBcf = (Λ x ys. c(fx)ys)"


subsection ‹Lemmas›

lemma cont_listfun_body [simp]:
  "cont (λg. Product_Type.fst (Rep_listfun g))"
  by (simp add: cont_Rep_listfun)

lemma cont_build_body [simp]:
  "cont (λg. Product_Type.snd (Rep_listfun g))"
  by (simp add: cont_Rep_listfun)

lemma build_Abs_listfun:
  assumes "abstract_list xs = f"
  shows "build(Abs_listfun (f, xs)) = xs"
  using assms and Abs_listfun_inverse [of "(f, xs)"]
  by (simp add: build_def)

lemma listfun_Abs_listfun [simp]:
  assumes "abstract_list xs = f"
  shows "listfun(Abs_listfun (f, xs)) = f"
  using assms and Abs_listfun_inverse [of "(f, xs)"]
  by (simp add: listfun_def)

lemma augment_Abs_listfun [simp]:
  assumes "abstract_list xs = f"
  shows "augment(Abs_listfun (f, xs))ys = xs ++ ys"
  using assms and Abs_listfun_inverse [of "(f, xs)"]
  by (simp add: augment_def build_Abs_listfun)

lemma cont_augment_body [simp]:
  "cont (λg. Abs_cfun ((++) (Product_Type.snd (Rep_listfun g))))"
  by (simp add: cont_Rep_listfun)

lemma "fold/build":
  fixes g :: "('a, 'b) listfun"
  shows "foldrkz(buildg) = listfungkz"
proof -
  from Rep_listfun obtain f xs where
    "Rep_listfun g = (f, xs)" and "f = abstract_list xs" by blast
  then show ?thesis by (simp add: build_def listfun_def)
qed

lemma "foldr/augment":
  fixes g :: "('a, 'b) listfun"
  shows "foldrkz(augmentgxs) = listfungk(foldrkzxs)"
proof -
  from Rep_listfun obtain f ys where
    "Rep_listfun g = (f, ys)" and "f = abstract_list ys" by blast
  then show ?thesis
    by (simp add: augment_def build_def listfun_def)
qed

lemma "foldr/id":
  "foldr(:)[] = (Λ x. x)"
proof (rule cfun_eqI)
  fix xs :: "['a]"
  show "foldr(:)[]xs = (Λ x. x)xs"
    by (induction xs) simp+
qed

lemma "foldr/app":
  "foldr(:)ys = (Λ xs. xs ++ ys)"
proof (rule cfun_eqI)
  fix xs :: "['a]"
  show "foldr(:)ysxs = (Λ xs. xs ++ ys)xs" by (induct xs) simp+
qed

lemma "foldr/cons": "foldrkz(x:xs) = kx(foldrkzxs)" by simp
lemma "foldr/single": "foldrkz[x] = kxz" by simp
lemma "foldr/nil": "foldrkz[] = z" by simp

lemma cont_listfun_comp_body1 [simp]:
  "cont (λh. Abs_listfun (Λ c n. listfungc(listfunhcn), buildg ++ buildh))"
proof -
  have "h.
    (Λ c n. listfungc(listfunhcn), buildg ++ buildh)  {(f, xs). f = abstract_list xs}"
    by (simp add: "fold/build")
  from cont_Abs_listfun [OF this, of "λx. x"]
  show ?thesis by simp
qed

lemma cont_listfun_comp_body2 [simp]:
  "cont (λg. Abs_listfun (Λ c n. listfungc(listfunhcn), buildg ++ buildh))"
proof -
  have "g.
    (Λ c n. listfungc(listfunhcn), buildg ++ buildh)  {(f, xs). f = abstract_list xs}"
    by (simp add: "fold/build")
  from cont_Abs_listfun [OF this, of "λx. x"]
  show ?thesis by simp
qed

lemma cont_listfun_comp_body [simp]:
  "cont (λg. Λ h. Abs_listfun (Λ c n. listfungc(listfunhcn), buildg ++ buildh))"
  by (rule cont2cont_LAM) simp+

lemma abstract_list_build_append:
  "abstract_list (buildg ++ buildh) = (Λ c n. listfungc(listfunhcn))"
  by (intro cfun_eqI) (simp add: "fold/build")

lemma "augment/build":
  "augmentg(buildh) = build(g ∘lf h)"
  by (simp add: listfun_comp_def augment_def build_Abs_listfun [OF abstract_list_build_append])

lemma "augment/nil":
  "augmentg[] = buildg"
  by (simp add: augment_def)

lemma build_listfun_comp [simp]:
  "build(g ∘lf h) = buildg ++ buildh"
  unfolding "augment/build" [symmetric]
  by (simp add: augment_def)

lemma augment_augment:
  "augmentg(augmenthxs) = augment(g ∘lf h)xs"
  by (simp add: augment_def)

lemma abstract_list_map [simp]:
  "abstract_list (mapfxs) = (Λ c n. foldr(mapFBcf)nxs)"
  by (intro cfun_eqI, induct xs) simp+

lemma "map":
  "mapfxs = build(Abs_listfun (Λ c n. foldr(mapFBcf)nxs, mapfxs))"
  by (simp add: build_Abs_listfun)

lemma "mapList":
  "foldr(mapFB(:)f)[] = mapf"
  by (rule cfun_eqI, rename_tac x, induct_tac x) simp+

lemma "mapFB":
  "mapFB(mapFBcf)g = mapFBc(f oo g)"
  by simp

lemma "++":
  "xs ++ ys = augment(Abs_listfun (abstract_list xs, xs))ys"
  by simp

subsection ‹Examples›

fixrec sum :: "[Integer]  Integer" where
  "sumxs = foldr(+)0xs"

fixrec down' :: "Integer  (Integer  'a  'a)  'a  'a" where
  "down'vcn = If le1v then cv(down'(v - 1)cn) else n"
declare down'.simps [simp del]

lemma down'_strict [simp]: "down' = " by (fixrec_simp)

definition down :: "'b itself  Integer  [Integer]" where
  "down C_type = (Λ v. build(Abs_listfun (
    (down' :: Integer  (Integer  'b  'b)  'b  'b)v,
    down'v(:)[])))"

lemma abstract_list_down' [simp]:
  "abstract_list (down'v(:)[]) = down'v"
proof (intro cfun_eqI)
  fix c :: "Integer  'b  'b" and n :: "'b"
  show "(abstract_list (down'v(:)[]))cn = down'vcn"
  proof (cases "le1v")
    assume "le1v = " then show ?thesis by simp
  next
    assume "le1v = FF" then show ?thesis
      by (subst (1 2) down'.simps) simp
  next
    have "le(0::Integer)1 = TT" by simp
    moreover assume "le1v = TT"
    ultimately have "le0v = TT" by (rule le_trans)
    then show ?thesis
      by (induct v rule: nonneg_Integer_induct)
         (subst (1 2) down'.simps, simp)+
  qed
qed

lemma cont_Abs_listfun_down' [simp]:
  "cont (λv. Abs_listfun (down'v, down'v(:)[]))"
proof -
  have "v. (down'v, down'v(:)[])  {(f, xs). f = abstract_list xs}" by simp
  from cont_Abs_listfun [OF this, of id] show ?thesis by simp
qed

lemma sum_down:
  "sum((down TYPE(Integer))v) = down'v(+)0"
  by (simp add: down_def "fold/build")

end