1
votes

I am a newbie in Haskell and study type classes now. I created a simple type class but unfortunately I am not able to fix

Couldn't match expected type

-- So a can be Int, Float etc
data MyShape a = Circle a -- etc like | Rectangle a a 
  deriving(Show)

class Geo a where
  inflate :: Num b => a -> b -> a
  area :: Num b => a -> b

instance Num a => Geo (MyShape a) where
  inflate (Circle r) x = Circle (r * x)
  area (Circle r) = 3 * r * r

It does not like both inflate and area functions.

Error:

• Couldn't match expected type ‘a’ with actual type ‘b’
      ‘b’ is a rigid type variable bound by
        the type signature for:
          inflate :: forall b. Num b => MyShape a -> b -> MyShape a
        at test2.hs:122:3-9
      ‘a’ is a rigid type variable bound by
        the instance declaration
        at test2.hs:121:10-33
    • In the second argument of ‘(*)’, namely ‘x’
      In the first argument of ‘Circle’, namely ‘(r * x)’
      In the expression: Circle (r * x)
    • Relevant bindings include
        x :: b (bound at test2.hs:122:22)
        r :: a (bound at test2.hs:122:19)
        inflate :: MyShape a -> b -> MyShape a (bound at test2.hs:122:3)
    |
122 |   inflate (Circle r) x = Circle (r * x)
    |                                      ^
1
Can you show the full error? - Willem Van Onsem
Couldn't match expected type ‘a’ with actual type ‘b’ ‘b’ is a rigid type variable bound by the type signature for: inflate :: forall b. Num b => MyShape a -> b -> MyShape a at test2.hs:122:3-9 ‘a’ is a rigid type variable bound by the instance declaration at test2.hs:121:10-33 • In the second argument of ‘(*)’, namely ‘x’ In the first argument of ‘Circle’, namely ‘(r * x)’ In the expression: Circle (r * x) - Stefan Dorn
Please put the error in your post above. As you can see, the unformatted version is difficult to read. - Michael Litchard

1 Answers

6
votes

The problem is that operations like (+) :: Num a => a -> a -> a, and (*) :: Num a => a -> a -> a require that the operands have the same type. You can not add an Int and an Integer together, nor can you multiple a Float with a Double. There exist some conversions like fromIntegral :: (Integral a, Num b) => a -> b, but these, to the best of my knowledge, can not convert an arbitrary Num type to an arbitrary Num type, and furthermore it can result in imprecisions. For example, by converting an Integer to a Float, you could "lose data".

Your inflate :: (Geo a, Num b) => a -> b -> a function, for example, thus results in two different types, the type of the inflate constant x, and the type of the values in the circle. Both are Num types, but not per se the same type.

We can for example make MyShape an instance of a class Geo like:

class Geo a where
  inflate :: Num b => a b -> b -> a b
  area :: Num b => a b -> b

and then define an instance like:

instance Geo MyShape where
  inflate (Circle r) x = Circle (r * x)
  area (Circle r) = 3 * r * r

So here we specified that for a MyShape b with Num b, that there is an inflate :: Num b => MyShape b -> b -> MyShape b, the same for area :: Num b => MyShap b -> b.