Search code examples
haskellclasstype-systems

An error with Haskell classes I fall all the time and can't understand


there's an error I come across all the time but can't understand how to make it right. An example of code that gives me this error is:

class Someclass a where
    somefunc :: (Num b) => b -> a -> a

data Sometype = Somecons Int

instance Someclass Sometype where
    somefunc x (Somecons y) = Somecons (x+y)

The error message is:

Couldn't match expected type 'b' against inferred type 'Int'
'b' is a rigid type variable bound by the type signature for 'somefunc' at error.hs:3:21
In the second argument of '(+)', namely 'y'
In the first argument of 'Somecons', namely '(x + y)'
In the expression: Somecons (x + y)

I understand that the error message is trying to tell me that I used a name of type Int where he was expecting something with type (Num b) => b. What I can't understand is that Int fits in (Num b)=>b. Shouldn't the compiler understand what I'm telling him (that for this specific instance b should be an integer? How can I make this fit?

Coment: Of course in this specific example I could have made somefunc with type signature:

somefunc :: a -> a-> a 

but supose I wanted something like:

data Newtype = Newcons (Int, Int) 

instance Someclass Newtype where
    somefunc x (Newtype (y,z) ) = Newtype (y+x, z)

Things like that recurrently happens when I'm trying to do something in haskell.


Solution

  • Well, you can make the point clearer when thinking of the generics notation using universal quantification.

    somefunc :: (Num b) => b -> a -> a
    

    therefore means nothing but

    somefunc :: forall a b . Num b => b -> a -> a
    

    This means your class function must be defined for any numeric b.

    The code

    Data Sometype = Somecons Int
    
    instance Someclass Sometype where
        somefunc x (Somecons y) = Somecons (x+y)
    

    forces b to have one concrete type - Int, which doesn't conform with the requirement to work for any numeric type.

    You might want to have something like this

    class Num b => SomeClass a b where
        somefunc :: b -> a -> a
    
    instance Someclass Somecons Int where
        -- ...