I have a class “Shape” which should have “area” defined on all instances. area returns “Area b” (a data type) that contains a number (b belongs to Num typeclass) signifying the area of that Shape.
Haskell has problem binding that b to (x*y) where x and y are of type ‘a’ and ‘a’ is also of typeclass Num.
How do I solve this ?? [If i replace (x*y) by 0, it works but doesn’t work even with (0::Int)]
Code :
data Unit = Unit | Meter | CentiMeter deriving Show
data Area a = Area a Unit deriving Show
class Shape a where
area :: (Num b) => a -> Area b
data Rectangle side = Rectangle side side Unit deriving Show
instance (Num a) => Shape (Rectangle a) where
area (Rectangle x y unit) = Area (x*y) unit
Error :
[1 of 1] Compiling Main ( y.hs, interpreted )
y.hs:11:46:
Could not deduce (a ~ b)
from the context (Num a)
bound by the instance declaration at y.hs:10:10-39
or from (Num b)
bound by the type signature for
area :: Num b => Rectangle a -> Area b
at y.hs:11:10-52
`a' is a rigid type variable bound by
the instance declaration at y.hs:10:15
`b' is a rigid type variable bound by
the type signature for area :: Num b => Rectangle a -> Area b
at y.hs:11:10
In the second argument of `(*)', namely `y'
In the first argument of `Area', namely `(x * y)'
In the expression: Area (x * y) unit
Failed, modules loaded: none.
The problem here is
area‘s type signature:What it says is “give me an
a, and I’ll give you anArea bfor anybyou want; you can pick”. So, for instance, I could giveareaanIntegerand expect back anArea Double. Clearly, this isn’t what you want!In this case, the error arises because you use
x*y, which has type a, when b is expected — you have to give a value that works for any numeric type b, but you’re giving a value that only works for one (a).If you changed
area‘s type toa -> Area Integer, or such, then it would work. However, I have a feeling you want the instance to be able to specify what the type of the area is. For this, you’ll need to use a language extension called type families:This says that for every type a that’s an instance of
Shape, there is an associated typeAreaComponent a, representing the type of each component of its area. That type is required to be an instance ofNumby the definition ofShape.Another thing you could do, if all your shapes take a numeric type parameter, is to make the instances be for the type constructors of each shape, rather than the full shape types themselves: