Theory Data_Tuple

section ‹Data: Tuple›

theory Data_Tuple
  imports
    Type_Classes
    Data_Bool
begin

subsection ‹Datatype definitions›

domain Unit ("⟨⟩") = Unit ("⟨⟩")

domain ('a, 'b) Tuple2 ("_, _") =
  Tuple2 (lazy fst :: "'a") (lazy snd :: "'b") ("_, _")

notation Tuple2 ("⟨,⟩")

fixrec uncurry :: "('a  'b  'c)  'a, 'b  'c"
  where "uncurryfp = f(fstp)(sndp)"

fixrec curry :: "('a, 'b   'c)  'a  'b  'c"
  where "curryfab = fa, b"

domain ('a, 'b, 'c) Tuple3 ("_, _, _") =
  Tuple3 (lazy "'a") (lazy "'b") (lazy "'c") ("_, _, _")

notation Tuple3 ("⟨,,⟩")

subsection ‹Type class instances›

instantiation Unit :: Ord_linear
begin

definition
  "eq = (Λ ⟨⟩ ⟨⟩. TT)"

definition
  "compare = (Λ ⟨⟩ ⟨⟩. EQ)"

instance
  apply standard
        apply (unfold eq_Unit_def compare_Unit_def)
        apply simp
       apply (rename_tac x, case_tac x, simp, simp)
      apply (rename_tac x y, case_tac x, simp, case_tac y, simp, simp)
     apply (rename_tac x y, case_tac x, case_tac y, simp, simp, case_tac y, simp, simp)
    apply (rename_tac x y, case_tac x, simp, case_tac y, simp, simp)
   apply (rename_tac x, case_tac x, simp, simp)
  apply (rename_tac x y z, case_tac x, simp, case_tac y, simp, case_tac z, simp, simp)
  done

end

instantiation Tuple2 :: (Eq, Eq) Eq_strict
begin

definition
  "eq = (Λ x1, y1 x2, y2. eqx1x2 andalso eqy1y2)"

instance proof
  fix x :: "'a, 'b"
  show "eqx = "
    unfolding eq_Tuple2_def by (cases x, simp_all)
  show "eqx = "
    unfolding eq_Tuple2_def by simp
qed

end

lemma eq_Tuple2_simps [simp]:
  "eqx1, y1x2, y2 = (eqx1x2 andalso eqy1y2)"
  unfolding eq_Tuple2_def by simp

instance Tuple2 :: (Eq_sym, Eq_sym) Eq_sym
proof
  fix x y :: "'a, 'b"
  show "eqxy = eqyx"
    unfolding eq_Tuple2_def
    by (cases x, simp, (cases y, simp, simp add: eq_sym)+)
qed

instance Tuple2 :: (Eq_equiv, Eq_equiv) Eq_equiv
proof
  fix x y z :: "'a, 'b"
  show "eqxx  FF"
    by (cases x, simp_all)
  show "eqxz = TT" if "eqxy = TT" and "eqyz = TT"
    using that
    by (cases x, simp, cases y, simp, cases z, simp, simp,
        fast intro: eq_trans)
qed

instance Tuple2 :: (Eq_eq, Eq_eq) Eq_eq
proof
  fix x y :: "'a, 'b"
  show "eqxx  FF"
    by (cases x, simp_all)
  show "x = y" if "eqxy = TT"
    using that by (cases x, simp, cases y, simp, simp, fast)
qed

instantiation Tuple2 :: (Ord, Ord) Ord_strict
begin

definition
  "compare = (Λ x1, y1 x2, y2.
    thenOrdering(comparex1x2)(comparey1y2))"

instance
  by standard (simp add: compare_Tuple2_def,
      rename_tac x, case_tac x, simp_all add: compare_Tuple2_def)

end

lemma compare_Tuple2_simps [simp]:
  "comparex1, y1x2, y2 = thenOrdering(comparex1x2)(comparey1y2)"
  unfolding compare_Tuple2_def by simp

instance Tuple2 :: (Ord_linear, Ord_linear) Ord_linear
proof
  fix x y z :: "'a, 'b"
  show "eqxy = is_EQ(comparexy)"
    by (cases x, simp, cases y, simp, simp add: eq_conv_compare)
  show "oppOrdering(comparexy) = compareyx"
    by (cases x, simp, cases y, simp, simp add: oppOrdering_thenOrdering)
  show "x = y" if "comparexy = EQ"
    using that by (cases x, simp, cases y, simp, auto elim: compare_EQ_dest)
  show "comparexz = LT" if "comparexy = LT" and "compareyz = LT"
    using that
    apply (cases x, simp, cases y, simp, cases z, simp, simp)
    apply (elim disjE conjE)
       apply (fast elim!: compare_LT_trans)
      apply (fast dest: compare_EQ_dest)
     apply (fast dest: compare_EQ_dest)
    apply (drule compare_EQ_dest)
    apply (fast elim!: compare_LT_trans)
    done
  show "comparexx  EQ"
    by (cases x, simp_all)
qed

instantiation Tuple3 :: (Eq, Eq, Eq) Eq_strict
begin

definition
  "eq = (Λ x1, y1, z1 x2, y2, z2.
    eqx1x2 andalso eqy1y2 andalso eqz1z2)"

instance proof
  fix x :: "'a, 'b, 'c"
  show "eqx = "
    unfolding eq_Tuple3_def by (cases x, simp_all)
  show "eqx = "
    unfolding eq_Tuple3_def by simp
qed

end

lemma eq_Tuple3_simps [simp]:
  "eqx1, y1, z1x2, y2, z2 = (eqx1x2 andalso eqy1y2 andalso eqz1z2)"
  unfolding eq_Tuple3_def by simp

instance Tuple3 :: (Eq_sym, Eq_sym, Eq_sym) Eq_sym
proof
  fix x y :: "'a, 'b, 'c"
  show "eqxy = eqyx"
    unfolding eq_Tuple3_def
    by (cases x, simp, (cases y, simp, simp add: eq_sym)+)
qed

instance Tuple3 :: (Eq_equiv, Eq_equiv, Eq_equiv) Eq_equiv
proof
  fix x y z :: "'a, 'b, 'c"
  show "eqxx  FF"
    by (cases x, simp_all)
  show "eqxz = TT" if "eqxy = TT" and "eqyz = TT"
    using that
    by (cases x, simp, cases y, simp, cases z, simp, simp,
        fast intro: eq_trans)
qed

instance Tuple3 :: (Eq_eq, Eq_eq, Eq_eq) Eq_eq
proof
  fix x y :: "'a, 'b, 'c"
  show "eqxx  FF"
    by (cases x, simp_all)
  show "x = y" if "eqxy = TT"
    using that by (cases x, simp, cases y, simp, simp, fast)
qed

instantiation Tuple3 :: (Ord, Ord, Ord) Ord_strict
begin

definition
  "compare = (Λ x1, y1, z1 x2, y2, z2.
    thenOrdering(comparex1x2)(thenOrdering(comparey1y2)(comparez1z2)))"

instance
  by standard (simp add: compare_Tuple3_def,
    rename_tac x, case_tac x, simp_all add: compare_Tuple3_def)

end

lemma compare_Tuple3_simps [simp]:
  "comparex1, y1, z1x2, y2, z2 =
    thenOrdering(comparex1x2)
      (thenOrdering(comparey1y2)(comparez1z2))"
  unfolding compare_Tuple3_def by simp

instance Tuple3 :: (Ord_linear, Ord_linear, Ord_linear) Ord_linear
proof
  fix x y z :: "'a, 'b, 'c"
  show "eqxy = is_EQ(comparexy)"
    by (cases x, simp, cases y, simp, simp add: eq_conv_compare)
  show "oppOrdering(comparexy) = compareyx"
    by (cases x, simp, cases y, simp, simp add: oppOrdering_thenOrdering)
  show "x = y" if "comparexy = EQ"
    using that by (cases x, simp, cases y, simp, auto elim: compare_EQ_dest)
  show "comparexz = LT" if "comparexy = LT" and "compareyz = LT"
    using that
    apply (cases x, simp, cases y, simp, cases z, simp, simp)
    apply (elim disjE conjE)
            apply (fast elim!: compare_LT_trans)
           apply (fast dest: compare_EQ_dest)
          apply (fast dest: compare_EQ_dest)
         apply (fast dest: compare_EQ_dest)
        apply (fast dest: compare_EQ_dest)
       apply (drule compare_EQ_dest)
       apply (fast elim!: compare_LT_trans)
      apply (fast dest: compare_EQ_dest)
     apply (fast dest: compare_EQ_dest)
    apply (fast dest: compare_EQ_dest elim!: compare_LT_trans)
    done
  show "comparexx  EQ"
    by (cases x, simp_all)
qed

end