6. Type Classes

Created Saturday 23 August 2014

Overview

Type Class Instances

elem :: Eq a => a -> [a] -> Bool

elem _ [] = False
elem x (y : ys)
| x == y = True
| otherwise = elem x ys

data RGB = RGB Int Int Int

colors = [RGB 255 0 0, RGB 0 255 0, RGB 0 0 255]
green = RGB 0 255 0
greenInColors = elem green colors --WON'T work -> RGB type isn't in the Eq type class
elem :: Eq a => a -> [a] -> Bool
data RGB = RGB Int Int Int
instance Eq RGB where
(RGB r1 g1 b1) == (RGB r2 g2 b2) =
(r1 == r2) && (g1 == g2) && (b1 == b2)
To show RGB as a string
instance Show RGB where
show (RGB r g b) =
"RGB" ++ (show r) ++ " " ++
(show g) ++ " " ++ (show b)

Type Class Instances for Parameterized Types

data Maybe' a = Nothing' | Just' a
Instance with a contract
instance (Eq a) => Eq (Maybe' a) where
Nothing' == Nothing' = True
Nothing' == (Just' _) = False
(Just' _) == Nothing' = False
(Just' x) == (Just' y) = x == y

Deriving Type Class Instances

data RGB = RGB Int Int Int
instance Eq RGB where
(RGB r1 g1 b1) == (RGB r2 g2 b2) =
(r1 == r2) && (g1 == g2) && (b1 == b2)

data Person = Person String Int Int
instance Eq Person where
(Person name1 age1 height1) ==
(Person name2 age2 height2) =
(name1 == name2) && (age1 == age2) &&
(height1 == height2)
DERIVING:
data RGB = RGB Int Int Int
deriving Eq

ERROR: equality test for function doesn't exist
data Foo = Foo (Int -> Int)
deriving Eq --ERROR

Defining Type Classes

class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
--Default implementations — thus it's possible to define only instance of '==' or '/='
x /= y = not (x == y)
x == y = not (x /= y)

Overloading

Same name for different types provides different behavior
data Point2 = Point2 Double Double
data Point3 = Point3 Double Double Double
distance2 :: Point2 -> Point2 -> Double
distance2 (Point x1 y1) (Point2 x2 y2) =
sqrt (dx * dx + dy * dy)
where dx = x1 - x2
dy = y1 - y2
distance3 :: Point3 -> Point3 -> Double
distance3 (Point3 x1 y1 z1) (Point3 x2 y2 z2) =
sqrt (dx * dx + dy * dy + dz * dz)
where dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
The above functions do the same thing and should be one function
class Measurable a where
distance :: a -> a -> Double

instance Measurable Point2 where
distance = distance2

instance Measurable Double where
distance x y = abs (x - y)

pathLength :: Measurable a => [a] -> Double
pathLength [] = 0
pathLength (_ : []) = 0
pathLength (p0 : p1 : ps) =
distance p0 p1 + pathLength (p1 : ps)

Subclasses of Type Classes

class (Eq a) => Ord a where
(<) :: a -> a -> Bool
(>) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>=) :: a -> a -> Bool
compare :: a -> a -> Ordering
max :: a -> a -> a
min :: a -> a -> a

data Ordering = LT | EQ | GT

class Measurable a where
distance :: a -> a -> Double

data Point2 = Point2 Double Double
deriving Show
data Point3 = Point3 Double Double Double
deriving Show

class (Measurable a, Show a) => Directions a where
getDirections :: a -> a -> String
getDirections p1 p2 =
"Go from " ++ (show p1) ++
" towards " ++ (show p2) ++
" and stop after " ++ (show (distance p1 p2))

instance Directions Point3 where
getDirections p1 p2 =
"Fly from " ++ (show p1) ++
" towards " ++ (show p2) ++
" and stop after " ++ (show (distance p1 p2))
If we want to use the default function then we have to define only an empty instance
instance Directions Point2 where



Backlinks: