Reputation: 123
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
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
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
Reputation: 476574
Should I add a comparation between
Constructor1
andConstructor2
. 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 Example
s. 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