Using GADTs, I have defined a depth-indexed tree data type (2–3 tree). The depth is there to statically ensure that the trees are balanced.
-- Natural numbers
data Nat = Z | S Nat
-- Depth-indexed 2-3 tree
data DT :: Nat -> Type -> Type where
-- Pattern of node names: N{#subtrees}_{#containedValues}
N0_0 :: DT Z a
N2_1 :: DT n a -> a -> DT n a
-> DT (S n) a
N3_2 :: DT n a -> a -> DT n a -> a -> DT n a
-> DT (S n) a
deriving instance Eq a => Eq (DT n a)
Now, some operations (e.g. insertion) might or might not change the depth of the tree. So I want to hide it from the type signature. I do this using existential data types.
-- 2-3 tree
data T :: Type -> Type where
T :: {unT :: DT n a} -> T a
insert :: a -> T a -> T a
insert x (T dt) = case dt of
N0_0 -> T $ N2_1 N0_0 x N0_0
{- ... -}
So far so good. My problem is:
I don't see how I can now define Eq on T.
instance Eq a => Eq (T a) where
(T x) == (T y) = _what
Obviously, I would like to do something like this:
(T {n = nx} x) == (T {n = ny} y)
| nx == ny = x == y
| otherwise = False
I don't know how / whether I can bind the type variables in the patter match. And I am neither sure how to compare them once I get them.
(I suspect Data.Type.Equality is for this, but I haven't seen any example of it in use.)
So, is there a way to implement the Eq (T a) instance, or is there some other approach that is recommended in this case?