Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typeclasses, overloading and instance declaration

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

like image 571
t0ma5 Avatar asked Mar 20 '23 22:03

t0ma5


1 Answers

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.

like image 191
GS - Apologise to Monica Avatar answered Apr 07 '23 02:04

GS - Apologise to Monica