문제

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 Ints.

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top