Theory FunctorClass

Up to index of Isabelle/HOL/Constructor

theory FunctorClass
imports Coerce TypeApp
begin

header {* Functor Class *}

theory FunctorClass
imports Coerce TypeApp
begin

subsection {* Class axioms *}

consts
  rep_fmap :: "(U => U) => U•'f => U•'f::tycon"

axclass functor < tycon
  rep_fmap_type:
    "[|!!x. x ::: A ==> f x ::: B; emb (xs::U•'f::tycon) ::: tc TYPE('f) A|]
      ==> emb (rep_fmap f xs) ::: tc TYPE('f) B"

  rep_fmap_cast:
    "rep_fmap (cast A) (xs::U•'f::tycon) =
      proj (cast (tc TYPE('f) A) (emb xs))"
 (* "emb (xs::U•'f::tycon) ::: tc TYPE('f) A ==> rep_fmap (cast A) xs = xs" *)

  rep_fmap_fmap:
    "rep_fmap f (rep_fmap g xs) = rep_fmap (λx. f (g x)) xs"

subsection {* @{term fmap} *}

constdefs
  fmap :: "('a => 'b) => 'a•'f => 'b•'f::functor"
  "fmap ≡ λf xs. coerce (rep_fmap (emb o f o proj) (coerce xs::U•'f))"

lemmas tc_rep_of = rep_of_App[symmetric]

lemmas rep_fmap_type2 =
  rep_fmap_type
    [of "rep_of TYPE('b)" _ "rep_of TYPE('c)",
       simplified tc_rep_of, standard]

theorem fmap_id [simp]: "fmap id xs = xs"
 apply (simp add: fmap_def o_def)
 apply (simp add: emb_proj)
 apply (subst rep_fmap_cast)
 apply (subst rep_of_App [symmetric])
 apply (simp add: coerce_def cast_rep_of)
done

lemmas fmap_ident [simp] = fmap_id [unfolded id_def]

theorem fmap_fmap:
  "fmap f (fmap g xs) = fmap (λx. f (g x)) xs"
 apply (simp add: fmap_def)
 apply (subst coerce_inverse)
  apply (rule rep_fmap_type2, simp)
  apply (rule coerce_type, simp)
 apply (simp add: rep_fmap_fmap o_def)
done

lemma fmap_comp: "fmap (f o g) = fmap f o fmap g"
by (simp add: o_def fmap_fmap)

lemma inj_fmap: "inj f ==> inj (fmap f)"
 apply (rule_tac g="fmap (inv f)" in inj_on_inverseI)
 apply (simp add: fmap_fmap)
done


subsection {* Proving that @{term "fmap coerce = coerce"} *}

lemma rep_fmap_eq_fmap: "rep_fmap = fmap"
by (simp add: fmap_def)

lemma in_rep_of_App_U:
  "xs ::: tc TYPE('f::tycon) A ==> xs ::: rep_of TYPE(U•'f)"
 apply (erule rev_subidemD)
 apply (simp add: rep_of_App)
 apply (rule monoD [OF mono_tc])
 apply (rule less_rep_of_U)
done

lemma rep_fmap_cast_rep_of:
  "rep_fmap (cast (rep_of TYPE('a))) =
    proj o cast (rep_of TYPE('a•'f::functor)) o (emb::U•'f => U)"
by (rule ext, simp add: rep_fmap_cast rep_of_App)

lemma rep_fmap_comp:
  "(rep_fmap (f o g) :: U•'f::functor => U•'f) = rep_fmap f o rep_fmap g"
by (simp add: rep_fmap_eq_fmap fmap_comp)

lemma coerce_coerce:
  "(emb o (coerce::'a => 'b) o proj :: U => U)
    = cast (rep_of TYPE('b)) o cast (rep_of TYPE('a))"
 apply (rule ext, simp)
 apply (simp only: coerce_def emb_proj)
done

lemma fmap_coerce: "fmap coerce = (coerce::'a•'f => 'b•'f::functor)"
 apply (rule ext)
 apply (simp add: fmap_def)
 apply (subst coerce_coerce)
 apply (subst rep_fmap_comp)
 apply (simp add: rep_fmap_cast_rep_of)
 apply (simp add: cast_rep_of)
 apply (simp add: coerce_def)
done


subsection {* Functor locale *}

text {*
  It is easy to prove instances of the functor class:
  All you need to do is define @{term tc} and @{term rep_fmap}
  in a standard way, and then prove that the functor laws
  hold at one specific type.
*}

constdefs
  functor_tc :: "((U => U) => 'l => 'l) => monotc"
  "functor_tc umap ≡ Abs_monotc (λA. Abs_idem (emb o umap (cast A) o proj))"

  rep_fmap_of :: "((U => U) => 'l => 'l) => ((U => U) => U•'f => U•'f::tycon)"
  "rep_fmap_of umap ≡ λf. coerce o umap f o coerce"

locale functor_locale =
  fixes umap :: "(U => U) => 'l => 'l"
assumes tc_umap:   "monotc TYPE('f::tycon) ≡ functor_tc umap"
    and rep_fmap:  "rep_fmap :: (U => U) => U•'f => U•'f::tycon
                      ≡ rep_fmap_of umap"
    and umap_id:   "!!xs. umap id xs = xs"
    and umap_umap: "!!f g xs. umap f (umap g xs) = umap (λx. f (g x)) xs"

lemma (in functor_locale) cast_tc:
  "cast (tc TYPE('f::tycon) A) = emb o umap (cast A) o proj"
 apply (unfold tc_def tc_umap functor_tc_def)
 apply (subst Abs_monotc_inverse)
  apply (simp)
  apply (rule monoI)
  apply (rule subidemI)
  apply (simp add: in_idem_def)
  apply (simp add: cast_Abs_idem idempotent_def umap_umap)
  apply (erule subst)
  apply (simp add: umap_umap)
  apply (subst cast_fixed)
   apply (erule subidemD)
   apply (rule cast_in_idem)
  apply (rule refl)
 apply (subst cast_Abs_idem)
  apply (simp add: idempotent_def umap_umap)
 apply (rule refl)
done

lemma (in functor_locale) rep_of_App_U_functor [simp]:
  "rep_of TYPE('l) = rep_of TYPE(U•'f::tycon)"
 apply (rule idempotent_equality, rule ext)
 apply (simp add: rep_of_App)
 apply (simp add: cast_tc cast_rep_of)
 apply (simp add: umap_id [unfolded id_def])
done

lemma (in functor_locale) in_tc_iff:
  "(x ::: tc TYPE('f::tycon) A) = (emb (umap (cast A) (proj x)) = x)"
by (simp add: in_idem_def cast_tc)

lemma (in functor_locale) emb_in_tc:
  "(emb (x::'l) ::: tc TYPE('f::tycon) A) = (umap (cast A) x = x)"
by (simp add: in_tc_iff coerce_def)

lemma (in functor_locale) emb_in_tc_2:
  "(emb (x::U•'f) ::: tc TYPE('f::tycon) A) =
    (umap (cast A) (coerce x) = coerce x)"
 apply (simp add: in_tc_iff coerce_def)
 apply safe
  apply (erule subst, rule emb_inverse[symmetric])
 apply simp
done

lemma (in functor_locale) umap_type:
  "emb (umap g xs) ::: rep_of TYPE(U•'f::tycon)"
by (simp add: rep_of_App in_tc_iff cast_rep_of_U umap_id)

theorem (in functor_locale) type:
fixes xs :: "U•'f::tycon"
assumes P: "!!x. x ::: A ==> f x ::: B"
shows "emb xs ::: tc TYPE('f) A ==> emb (rep_fmap f xs) ::: tc TYPE('f) B"
 apply (simp add: rep_fmap rep_fmap_of_def)
 apply (erule in_idemE)
 apply (rule in_idemI)
 apply (simp add: cast_tc)
 apply (simp add: coerce_def)
 apply (simp add: umap_umap)
 apply (rule_tac x="proj y" in fun_cong)
 apply (rule_tac f=umap in arg_cong)
 apply (rule ext)
 apply (rule cast_fixed)
 apply (rule P [OF cast_in_idem])
done


lemma (in functor_locale) cast:
fixes xs :: "U•'f::tycon"
shows "rep_fmap (cast A) xs = proj (cast (tc TYPE('f) A) (emb xs))"
by (simp add: rep_fmap cast_tc rep_fmap_of_def coerce_def)
(*
lemma (in functor_locale) cast:
fixes xs :: "U•'f::tycon"
shows "emb xs ::: tc TYPE('f) A ==> rep_fmap (cast A) xs = xs"
by (simp add: rep_fmap rep_fmap_of_def emb_in_tc_2)
*)
lemma (in functor_locale) comp:
fixes xs :: "U•'f::tycon"
shows "rep_fmap f (rep_fmap g xs) = rep_fmap (λx. f (g x)) xs"
by (simp add: rep_fmap rep_fmap_of_def umap_umap)

lemma (in functor_locale) functor_class:
  "OFCLASS('f::tycon, functor_class)"
 apply (intro_classes)
   apply (rule type, fast, assumption)
  apply (rule cast)
 apply (rule comp)
done

text {* Isomorphism at other type instances *}

lemma (in functor_locale) rep_of_App_functor:
  fixes map_aU :: "('a => U) => 'k => 'l"
  fixes map_Ua :: "(U => 'a) => 'l => 'k"
  assumes 1: "!!xs. emb xs = emb (map_aU emb xs)"
  assumes 2: "!!u. proj u = map_Ua proj (proj u)"
  assumes 3: "!!f g xs. map_aU f (map_Ua g xs) = umap (λx. f (g x)) xs"
  shows "rep_of TYPE('k) = rep_of TYPE('a•'f::tycon)"
 apply (rule idempotent_equality, rule ext)
 apply (simp add: rep_of_App)
 apply (simp add: cast_tc cast_rep_of)
 apply (simp add: prems)
done

lemma functor_locale_fmap_def:
  fixes map_Ua :: "(U => 'a) => 'l => 'k"
  fixes map_Ub :: "(U => 'b) => 'l => 'm"
  fixes map_ab :: "('a => 'b) => 'k => 'm"
  fixes map_bU :: "('b => U) => 'm => 'l"
  fixes map_UU :: "(U => U) => 'l => 'l"
  assumes fl: "functor_locale TYPE('f::functor) map_UU"
  assumes rews:
    "!!xs. emb xs = emb (map_bU emb xs)"
    "!!u. proj u = map_Ua proj (proj u)"
    "!!f g xs. map_ab f (map_Ua g xs) = map_Ub (λx. f (g x)) xs"
    "!!f g xs. map_bU f (map_Ub g xs) = map_UU (λx. f (g x)) xs"
  shows "fmap ≡ λf (xs::'a•'f::functor). coerce (map_ab f (coerce xs))"
 apply (rule eq_reflection, rule ext, rule ext)
 apply (unfold fmap_def)
 apply (simp add: fmap_coerce [symmetric])
 apply (simp add: fmap_def)
 apply (simp add: fl [THEN functor_locale.rep_fmap])
 apply (simp add: rep_fmap_of_def)
 apply (simp add: fl [THEN functor_locale.rep_of_App_U_functor])
 apply (simp add: fl [THEN functor_locale.umap_umap])
 apply (simp add: coerce_def rews)
done

end

Class axioms

@{term fmap}

lemmas tc_rep_of:

  tc TYPE('m1) (rep_of TYPE('a1)) = rep_of TYPE('a1 $ 'm1)

lemmas tc_rep_of:

  tc TYPE('m1) (rep_of TYPE('a1)) = rep_of TYPE('a1 $ 'm1)

lemmas rep_fmap_type2:

  [| !!x. x ::: rep_of TYPE('b) ==> f x ::: rep_of TYPE('c);
     emb xs ::: rep_of TYPE('b $ 'a) |]
  ==> emb (rep_fmap f xs) ::: rep_of TYPE('c $ 'a)

lemmas rep_fmap_type2:

  [| !!x. x ::: rep_of TYPE('b) ==> f x ::: rep_of TYPE('c);
     emb xs ::: rep_of TYPE('b $ 'a) |]
  ==> emb (rep_fmap f xs) ::: rep_of TYPE('c $ 'a)

theorem fmap_id:

  fmap id xs = xs

lemmas fmap_ident:

  fmap (λx. x) xs = xs

lemmas fmap_ident:

  fmap (λx. x) xs = xs

theorem fmap_fmap:

  fmap f (fmap g xs) = fmap (λx. f (g x)) xs

lemma fmap_comp:

  fmap (f o g) = fmap f o fmap g

lemma inj_fmap:

  inj f ==> inj (fmap f)

Proving that @{term "fmap coerce = coerce"}

lemma rep_fmap_eq_fmap:

  rep_fmap = fmap

lemma in_rep_of_App_U:

  xs ::: tc TYPE('f) A ==> xs ::: rep_of TYPE(U $ 'f)

lemma rep_fmap_cast_rep_of:

  rep_fmap (cast (rep_of TYPE('a))) = proj o cast (rep_of TYPE('a $ 'f)) o emb

lemma rep_fmap_comp:

  rep_fmap (f o g) = rep_fmap f o rep_fmap g

lemma coerce_coerce:

  emb o coerce o proj = cast (rep_of TYPE('b)) o cast (rep_of TYPE('a))

lemma fmap_coerce:

  fmap coerce = coerce

Functor locale

lemma cast_tc:

  functor_locale TYPE('f) umap
  ==> cast (tc TYPE('f) A) = emb o umap (cast A) o proj

lemma rep_of_App_U_functor:

  functor_locale TYPE('f) umap ==> rep_of TYPE('l) = rep_of TYPE(U $ 'f)

lemma in_tc_iff:

  functor_locale TYPE('f) umap
  ==> (x ::: tc TYPE('f) A) = (emb (umap (cast A) (proj x)) = x)

lemma emb_in_tc:

  functor_locale TYPE('f) umap
  ==> (emb x ::: tc TYPE('f) A) = (umap (cast A) x = x)

lemma emb_in_tc_2:

  functor_locale TYPE('f) umap
  ==> (emb x ::: tc TYPE('f) A) = (umap (cast A) (coerce x) = coerce x)

lemma umap_type:

  functor_locale TYPE('f) umap ==> emb (umap g xs) ::: rep_of TYPE(U $ 'f)

theorem type:

  [| functor_locale TYPE('f) umap; !!x. x ::: A ==> f x ::: B;
     emb xs ::: tc TYPE('f) A |]
  ==> emb (rep_fmap f xs) ::: tc TYPE('f) B

lemma cast:

  functor_locale TYPE('f) umap
  ==> rep_fmap (cast A) xs = proj (cast (tc TYPE('f) A) (emb xs))

lemma comp:

  functor_locale TYPE('f) umap
  ==> rep_fmap f (rep_fmap g xs) = rep_fmap (λx. f (g x)) xs

lemma functor_class:

  functor_locale TYPE('f) umap ==> OFCLASS('f, functor_class)

lemma rep_of_App_functor:

  [| functor_locale TYPE('f) umap; !!xs. emb xs = emb (map_aU emb xs);
     !!u. proj u = map_Ua proj (proj u);
     !!f g xs. map_aU f (map_Ua g xs) = umapx. f (g x)) xs |]
  ==> rep_of TYPE('k) = rep_of TYPE('a $ 'f)

lemma functor_locale_fmap_def:

  [| functor_locale TYPE('f) map_UU; !!xs. emb xs = emb (map_bU emb xs);
     !!u. proj u = map_Ua proj (proj u);
     !!f g xs. map_ab f (map_Ua g xs) = map_Ubx. f (g x)) xs;
     !!f g xs. map_bU f (map_Ub g xs) = map_UUx. f (g x)) xs |]
  ==> fmap == λf xs. coerce (map_ab f (coerce xs))