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.
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
-- ...
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 Int
s.
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 :-)
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.