Vonfry
Vonfry

Reputation: 365

how to instance Eq without deriving

Sorry about my poor English. The title may not explain what I mean.

In Data.Tree, Tree is defined as following:

-- | Multi-way trees, also known as /rose trees/.
data Tree a = Node {
        rootLabel :: a,         -- ^ label value
        subForest :: Forest a   -- ^ zero or more child trees
    }
#ifdef __GLASGOW_HASKELL__
  deriving (Eq, Read, Show, Data)
#else
  deriving (Eq, Read, Show)
#endif

It uses deriving to instance == and /= for Tree(date).

Could I do the same thing without deriving? I try things like this:

data Test a = Test a
instance Eq Test where
    (Test a) == (Test b) = a == b

But It throws an exception. I think the reason is about the types of a and b.

And what can I do whether I want to define a custom action for my data with ==.

I know I can use Functor with fmap to do it. But I want to use == like a == b where a = Test 1 and b = Test "a". Is it possible?

Upvotes: 3

Views: 2142

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476574

You can define an instance of Eq on Tree or Test, but there are some problems with your definition.

instance Eq Test where
    (Test a) == (Test b) = a == b

A first one is that Test in Eq Test is still parametrized. Indeed, you wrote data Test a = ... so that means that there is a type parameter. So you can specify it with:

instance Eq (Test a) where
    (Test y) == (Test x) = x == y

Now you thus specified that Eq is defined over Test a. I also renamed a and b to x and y. This is not necessary since the "type world" and "variable world" are separated, but it makes things less confusing.

But there is still a problem: you call x == y. But there is no guantee that a itself is an instance of Eq. You thus need to work with a type constraint:

instance Eq a => Eq (Test a) where
    (Test y) == (Test x) = x == y

Now you specify that Test a is an instance of Eq if a is an instance of Eq as well.

For your Tree data structure, the instance of Eq should thus look like:

instance (Eq a, Eq (Forest a)) => Eq (Tree a) where
    (Tree x1 y1) == (Tree x2 y2) = x1 == x2 && y1 == y2

(of course I here define how two trees are equal, it is possible that you want to define the equality over two trees in a (semantically) different way, so you should not per se copy paste this code).

Note that - like @luqui says - if type Forest a = [Tree a], then you can omit the Eq (Forest a) type constraint since instance Eq a => Eq [a] holds. So in that case it is:

instance Eq a => Eq (Tree a) where
    (Tree x1 y1) == (Tree x2 y2) = x1 == x2 && y1 == y2

Upvotes: 9

Related Questions