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 "uncurry⋅f⋅p = f⋅(fst⋅p)⋅(snd⋅p)"

fixrec curry :: "(⟨'a, 'b⟩  → 'c) → 'a → 'b → 'c"
  where "curry⋅f⋅a⋅b = f⋅⟨a, 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⟩. eq⋅x1⋅x2 andalso eq⋅y1⋅y2)"

instance proof
  fix x :: "⟨'a, 'b⟩"
  show "eq⋅x⋅⊥ = ⊥"
    unfolding eq_Tuple2_def by (cases x, simp_all)
  show "eq⋅⊥⋅x = ⊥"
    unfolding eq_Tuple2_def by simp
qed

end

lemma eq_Tuple2_simps [simp]:
  "eq⋅⟨x1, y1⟩⋅⟨x2, y2⟩ = (eq⋅x1⋅x2 andalso eq⋅y1⋅y2)"
  unfolding eq_Tuple2_def by simp

instance Tuple2 :: (Eq_sym, Eq_sym) Eq_sym
proof
  fix x y :: "⟨'a, 'b⟩"
  show "eq⋅x⋅y = eq⋅y⋅x"
    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 "eq⋅x⋅x ≠ FF"
    by (cases x, simp_all)
  show "eq⋅x⋅z = TT" if "eq⋅x⋅y = TT" and "eq⋅y⋅z = 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 "eq⋅x⋅x ≠ FF"
    by (cases x, simp_all)
  show "x = y" if "eq⋅x⋅y = 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⋅(compare⋅x1⋅x2)⋅(compare⋅y1⋅y2))"

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]:
  "compare⋅⟨x1, y1⟩⋅⟨x2, y2⟩ = thenOrdering⋅(compare⋅x1⋅x2)⋅(compare⋅y1⋅y2)"
  unfolding compare_Tuple2_def by simp

instance Tuple2 :: (Ord_linear, Ord_linear) Ord_linear
proof
  fix x y z :: "⟨'a, 'b⟩"
  show "eq⋅x⋅y = is_EQ⋅(compare⋅x⋅y)"
    by (cases x, simp, cases y, simp, simp add: eq_conv_compare)
  show "oppOrdering⋅(compare⋅x⋅y) = compare⋅y⋅x"
    by (cases x, simp, cases y, simp, simp add: oppOrdering_thenOrdering)
  show "x = y" if "compare⋅x⋅y = EQ"
    using that by (cases x, simp, cases y, simp, auto elim: compare_EQ_dest)
  show "compare⋅x⋅z = LT" if "compare⋅x⋅y = LT" and "compare⋅y⋅z = 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 "compare⋅x⋅x ⊑ EQ"
    by (cases x, simp_all)
qed

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

definition
  "eq = (Λ ⟨x1, y1, z1⟩ ⟨x2, y2, z2⟩.
    eq⋅x1⋅x2 andalso eq⋅y1⋅y2 andalso eq⋅z1⋅z2)"

instance proof
  fix x :: "⟨'a, 'b, 'c⟩"
  show "eq⋅x⋅⊥ = ⊥"
    unfolding eq_Tuple3_def by (cases x, simp_all)
  show "eq⋅⊥⋅x = ⊥"
    unfolding eq_Tuple3_def by simp
qed

end

lemma eq_Tuple3_simps [simp]:
  "eq⋅⟨x1, y1, z1⟩⋅⟨x2, y2, z2⟩ = (eq⋅x1⋅x2 andalso eq⋅y1⋅y2 andalso eq⋅z1⋅z2)"
  unfolding eq_Tuple3_def by simp

instance Tuple3 :: (Eq_sym, Eq_sym, Eq_sym) Eq_sym
proof
  fix x y :: "⟨'a, 'b, 'c⟩"
  show "eq⋅x⋅y = eq⋅y⋅x"
    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 "eq⋅x⋅x ≠ FF"
    by (cases x, simp_all)
  show "eq⋅x⋅z = TT" if "eq⋅x⋅y = TT" and "eq⋅y⋅z = 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 "eq⋅x⋅x ≠ FF"
    by (cases x, simp_all)
  show "x = y" if "eq⋅x⋅y = 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⋅(compare⋅x1⋅x2)⋅(thenOrdering⋅(compare⋅y1⋅y2)⋅(compare⋅z1⋅z2)))"

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]:
  "compare⋅⟨x1, y1, z1⟩⋅⟨x2, y2, z2⟩ =
    thenOrdering⋅(compare⋅x1⋅x2)⋅
      (thenOrdering⋅(compare⋅y1⋅y2)⋅(compare⋅z1⋅z2))"
  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 "eq⋅x⋅y = is_EQ⋅(compare⋅x⋅y)"
    by (cases x, simp, cases y, simp, simp add: eq_conv_compare)
  show "oppOrdering⋅(compare⋅x⋅y) = compare⋅y⋅x"
    by (cases x, simp, cases y, simp, simp add: oppOrdering_thenOrdering)
  show "x = y" if "compare⋅x⋅y = EQ"
    using that by (cases x, simp, cases y, simp, auto elim: compare_EQ_dest)
  show "compare⋅x⋅z = LT" if "compare⋅x⋅y = LT" and "compare⋅y⋅z = 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 "compare⋅x⋅x ⊑ EQ"
    by (cases x, simp_all)
qed

end