OnlyDavies
OnlyDavies

Reputation: 123

How to instantiate Eq (or any class) for a type with different constructors Haskell

I have a doubt about this thing.

If I have this type:

data Person = Person {name :: String, age :: Int} 

data Example = Constructor1 Integer | Constructor2 Person

I want to instantiate Eq class for Example

instantiate Eq Example where
(==) (Constructor1 e1) (Constructor1 e2) = e1 ==e2
(==) (Constructor2 e1) (Constructor2 e2) = e1 == e2

We can supposed that I have already instantiated the Eq class for Person, so I can compare Person with Person.

This is the way for instantiate a class with a type with multiple constructors?

And other doubt. Should I add a comparation between Constructor1 and Constructor2. I don't think so, because they could be from different types.

I'm talking about something like this stuff:

(==) (Constructor1 e1) (Constructor2 e2) == "no idea how to compare Person with Int"

Thank you!

Upvotes: 1

Views: 574

Answers (3)

Thilo
Thilo

Reputation: 262494

Should I add a comparation between Constructor1 and Constructor2?

You have to, otherwise your implementation of Eq would be incomplete.

After all your cases, just add

(==) _ _ = False

I don't think so, because they could be from different types.

But they are of the same type, they are both Example values.

So your Eq function needs to be able to compare them.

If you think it makes sense to have a Constructor1 number and a Constructor2 person be equal under some conditions you can write the appropriate predicate to do that. But that seems unusual and you should probably make your own typeclass for this kind of comparison instead of using Eq. If you do use Eq, make sure it satisfies reflexivity, transitivity and symmetry.


Also note that for "boring" mechanic Eq instances, the compiler can derive them automatically (and it will create the same thing you would have written anyway):

data Example = Constructor1 Integer | Constructor2 Person
  deriving Eq

You can also derive Show.

https://www.reddit.com/r/haskell/comments/28gxxz/how_does_deriving_eq_work/

Upvotes: 7

melpomene
melpomene

Reputation: 85767

Why don't you just do

data Example = Constructor1 Integer | Constructor2 Person
    deriving (Eq)

? Then the compiler will instantiate Eq for you.

If you want to do it manually, then yes, you should add a case for comparing different constructors. If the standard library didn't do this, then e.g. True == False would throw an exception (True and False are different constructors of the Bool type) and so would "hello" == "" ("" is [] (at type [Char]) and "hello" is 'h' : "ello", so again you have different constructors ([] and :)).

You can do it like this:

instance Eq Example where
    (==) (Constructor1 e1) (Constructor1 e2) = e1 == e2
    (==) (Constructor2 e1) (Constructor2 e2) = e1 == e2
    (==) _ _ = False

Upvotes: 3

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476574

Should I add a comparation between Constructor1 and Constructor2. I don't think so, because they could be from different types.

Well that is of course up to you, you could specify that Constructor1 i is equal to Constructor2 p given that age p == fromIntegral i, so that Constructor1 basically holds an "age" and Constructor2 is equal that constructor given the age of that person has that age, but that depends on what you consider two equal Examples. As long as your function satisfies the equivalence relation conditions there is no problem.

If you do not want any Constructor1 object to be equal to Constructor2, you should add a line that returns False in that case:

instance Eq Example where
    (==) (Constructor1 e1) (Constructor1 e2) = e1 == e2
    (==) (Constructor2 e1) (Constructor2 e2) = e1 == e2
    (==) _ _ = False

But you can save you the trouble in that specific case, and just write:

data Example = Constructor1 Integer | Constructor2 Person deriving Eq

Haskell then implement an instance Eq automatically, where two Example objects are considered equal given the data constructors are the same, and all the parameters are equal. In all other cases the two objects are considered not equal.

Upvotes: 5

Related Questions