0
votes

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.

4
huh... I guess you mean data ... instead of Data...R. Martinho Fernandes
Yes, sure. Thanks for the correction.Rafael S. Calsaverini

4 Answers

8
votes

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
    -- ...
5
votes

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.

3
votes

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 :-)

1
votes

To continue on Dario's example, what you seem to be asking for is:

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

That is, instead of the "you pick a type, and my function will work" promise that "forall b . Num b => b" implies, you want the "I'll pick a type, so my function will work" promise of "exists b . (Num b) => b", which Sr. Fernandes mentioned. More importantly, you aren't showing how your constraint (Num b) => b helps your case.

The really interestingsituation would be: how should you class handle the following type:

data BMephType i o = BMT (i -> (o, BMephType i o))
instance Someclass (BMephType (Complex Double -> String) String) where

Most likely, your solution will involve a Complex Double. Somewhere. If it only involves a Complex Double, and no other Num types, then you're looking for an existential type, not a universal.