views:

157

answers:

3

Hi, 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.

+5  A: 

The problem can be seen in the signature of the + operator:

(+) :: Num a => a -> a -> a

Because of this, when you use + in somefunc with an Int, it forces b to be an Int, and therefore somefunc becomes:

somefunc :: Int -> Sometype -> Sometype

To implement the Someclass class, somefunc is expected to have this signature:

somefunc :: Num b => b -> Sometype -> Sometype

That is, it should work with any type that is an instance of Num. Your function only works with Ints.

Martinho Fernandes
doesn't somefunc become `:: Int -> Sometype -> Sometype` ?
yairchu
@yairchu, yeah, that's it, thanks for the correction.
Martinho Fernandes
+7  A: 

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
    -- ...
Dario
+3  A: 

You cannot mix types, as (+) :: a → a → a

let x = 1.2::Double; y=2::Int in x + y

This will fail already.

Num is too general, if you specified that x::Double you could get it working by an explicit 'typecast' (fromIntegral )

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

I think you want something like this

instance Someclass Sometype where

    somefunc :: Int → Sometype → Int
    somefunc x (Somecons y) = Somecons (x + y)

btw, you need to type data instead of Data :-)

Exception e
The arrows and nice and all, but in Haskell there is no such thing. It's `->`.
Martinho Fernandes
I know, but it is common practice in the haskell literature to use the typographic symbols. Some haskell-editors even display these symbols the way I showcased.
Exception e
I see. I prefer `->` because it is copy-pastable (not that I think anyone will copy-paste such contrived example code).
Martinho Fernandes