Eyal
Eyal

Reputation: 5848

In Haskell, why do I need to specify the typeclass in an instance declaration?

The following doesn't compile:

data Point a b = Point { x :: a
                       , y :: b
                       } deriving (Show)

instance Eq (Point a b) where
  (Point x _) == (Point y _) = x == y

The error is:

No instance for (Eq a)
  arising from a use of `=='
In the expression: x == y
In an equation for `==': (Point x _) == (Point y _) = x == y
In the instance declaration for `Eq (Point a b)'

However, if I add the typeclass into the instance, then it works:

data Point a b = Point { x :: a
                       , y :: b
                       } deriving (Show)

instance (Eq a) => Eq (Point a b) where
  (Point x _) == (Point y _) = x == y

Can't the compiler see that I'm using a == a in there and deduce that a must be in the typeclass Eq?

Upvotes: 3

Views: 168

Answers (2)

alternative
alternative

Reputation: 13022

Imagine a function

equals ::  a -> a -> Bool
equals = (==)

The compiler can obviously infer that the type of equals should be Eq a => a -> a -> Bool. But it errors, because you declared that your type works for all a.

Typeclass instances are similar, except we don't have the option of letting them being inferred in the same way we could leave out the type declaration for equals. So it is necessary to specificy the constraint in the same way that if you specify the type signature of a function, you also have to specify the constraint.

That is, ghc won't infer only the constraint; it either has to infer the entire signature, or none of it. (Well, it infers either way, but the inference has to be more general than what you typed it as, if you typed it - and contraints fall under this requirement).

Think of your initial instance Eq (Point a b) as (==) :: (Point a b) -> (Point a b) -> Bool, which is impossible to well-define in the way that you like, since giving it that body would have (==) :: Eq a => (Point a b) -> (Point a b) -> Bool.

Upvotes: 5

Ben
Ben

Reputation: 71485

It can deuce that a must be in the type class Eq. That's exactly why it's complaining. You declared instance Eq (Point a b), which says that types of the form Point a b are in the Eq type class for any types a and b, but you gave a definition for == that only works when a is a member of Eq.

Those two things are inconsistent, so Haskell doesn't try to guess which one is what you really meant, it just reports it as an error. The language didn't have to work that way, but it's a deliberate design choice.

Upvotes: 15

Related Questions