Haskell: The Craft of Functional Programming
Simon Thompson
(c) Addison-Wesley, 1999.
Chapter 12
> module Chapter12 where
Overloading and type classes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why overloading?
^^^^^^^^^^^^^^^^
Testing for membership of a Boolean list.
> elemBool :: Bool -> [Bool] -> Bool
> elemBool x [] = False
> elemBool x (y:ys)
> = (x == y) || elemBool x ys
Testing for membership of a general list, with the equality function as a
parameter.
> elemGen :: (a -> a -> Bool) -> a -> [a] -> Bool
> elemGen eqFun x [] = False
> elemGen eqFun x (y:ys)
> = (eqFun x y) || elemGen eqFun x ys
Introducing classes
^^^^^^^^^^^^^^^^^^^
Definitions of classes cannot be hidden, so the definitions etc. here are not
executable.
class Eq a where
(==) :: a -> a -> Bool
Functions which use equality
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Testing for three values equal: more general than Int -> Int -> Int -> Bool.
> allEqual :: Eq a => a -> a -> a -> Bool
> allEqual m n p = (m==n) && (n==p)
elem :: Eq a => a -> [a] -> Bool
books :: Eq a => [ (a,b) ] -> a -> [b]
It is easier to see this typing if you remane books lookupFirst:
> lookupFirst :: Eq a => [ (a,b) ] -> a -> [b]
> lookupFirst ws x
> = [ z | (y,z) <- ws , y==x ]
borrowed :: Eq b => [ (a,b) ] -> b -> Bool
numBorrowed :: Eq a => [ (a,b) ] -> a -> Int
Signatures and Instances
^^^^^^^^^^^^^^^^^^^^^^^^
The Visible class:
> class Visible a where
> toString :: a -> String
> size :: a -> Int
A type is made a member or instance of a class by defining
the signature functions for the type. For example,
instance Eq Bool where
True == True = True
False == False = True
_ == _ = False
Declaring examples of the Visible class
> instance Visible Char where
> toString ch = [ch]
> size _ = 1
> instance Visible Bool where
> toString True = "True"
> toString False = "False"
> size _ = 1
An instance declaration with a context.
> instance Visible a => Visible [a] where
> toString = concat . map toString
> size = foldr (+) 1 . map size
Default definitions
^^^^^^^^^^^^^^^^^^^
To return to our example of equality, the Haskell equality class is in fact
defined by
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x==y)
x == y = not (x/=y)
Derived classes
^^^^^^^^^^^^^^^
Ordering is built on Eq.
class Eq a => Ord a where
(<), (<=), (>), (>=) :: a -> a -> Bool
max, min :: a -> a -> a
compare :: a -> a -> Ordering
This is the same definition as in Chapter7, but now with an overloaded type.
> iSort :: Ord a => [a] -> [a]
> iSort [] = []
> iSort (x:xs) = ins x (iSort xs)
To insert an element at the right place into a sorted list.
> ins :: Ord a => a -> [a] -> [a]
> ins x [] = [x]
> ins x (y:ys)
> | x <= y = x:(y:ys)
> | otherwise = y : ins x ys
Multiple constraints
^^^^^^^^^^^^^^^^^^^^
Sorting visible objects ...
> vSort :: (Ord a,Visible a) => [a] -> String
> vSort = toString . iSort
Similarly,
> vLookupFirst :: (Eq a,Visible b) => [(a,b)] -> a -> String
> vLookupFirst xs x = toString (lookupFirst xs x)
Multiple constraints can occur in an instance declaration, such as
instance (Eq a,Eq b) => Eq (a,b) where
(x,y) == (z,w) = x==z && y==w
Multiple constraints can also occur in the definition of a class,
> class (Ord a,Visible a) => OrdVis a
Can then give vSort the type:
vSort :: OrdVis a => [a] -> String
A tour of the built-in Haskell classes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For details of the code here, please see the standard Prelude and Libraries.
Types and Classes
^^^^^^^^^^^^^^^^^
The code in this section is not legal Haskell.
To evaluate the type of concat . map show, type
:type concat . map show
to the Hugs prompt.