Question

Having this:

data Rectangle = Rectangle Height Width
data Circle = Circle Radius

class Shape a where
    area :: a -> Float
    perimeter :: a -> Float

instance Shape Rectangle where
    area (Rectangle h w) = h * w
    perimeter (Rectangle h w) = 2*h+w*2

instance Shape Circle where
    area (Circle r) = pi * r**2
    perimeter (Circle r) = 2*pi*r

volumenPrism base height = (area base) * height

surfacePrism shape h = (area shape) * 2 + perimeter shape * h

Why cant I write this? a is a type so why doesn't this work?

instance (Shape a) => Eq a where
      x==y = area x == area y

Obviously doing like this:

instance Eq Circle where
     x==y = area x == area y

first for Circle and then for Rectangle works..but it seems not the right way.

What is it I don't get in all this?

Ty

Was it helpful?

Solution

The fundamental problem is that the type class instance resolution machinery doesn't backtrack. So if you write instance Shape a => Eq a, then whenever the compiler wants to find an Eq instance, the compiler will try to use this instance and for most types it won't work out because they aren't instances of Shape.

If you still really want to do this, you can add

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

at the top of your source file.

You can also work round some of the problems described above by also adding OverlappingInstances to the set of LANGUAGE pragmas, but you will still have a global instance for Eq that will cause significant confusion elsewhere in your program.

It's much better to just enumerate the instances you really need, even if it seems ugly. You can keep the boilerplate to a minimum with a helper function, e.g.

x `areaEq` y = area x == area y

and then

instance Eq Circle where
    (==) = areaEq

etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top