:
(+) :: Num a => a -> a -> a
This declaration asserts that (+) is of type a -> a -> a for any number type a . A type class, such as Num , has a collection of named methods, such as (+) , which can be defined differently for each instance of the type class. Type classes therefore provide for overloaded functions, functions with the same name but different definitions. Overloading is another kind of polymorphism.
Numbers are rather complicated, and are explained in more detail in the following chapter, so we illustrate type classes with a simpler type class
class Eq a where
(==),(/=) :: a -> a -> Bool
x /= y = not (x == y)
This introduces the Equality type class, members of which can use one and the same equality test (==) and inequality test (/=) . There is a default definition of (/=) as part of the class, so we only have to provide a definition of (==) .
To become a member of the Eq club we have to define an instance . For example,
instance Eq Bool where
x == y = if x then y else not y
instance Eq Person where
x == y = (pin x == pin y)
If pin :: Person -> Pin then we need Eq Pin for the last instance to be correct. Of course, we don’t have to make Person a member of the Equality club; we can always define
samePerson :: Person -> Person -> Bool
samePerson x y = (pin x == pin y)
But we can’t use (==) instead of samePerson unless we make an instance declaration.
Here are simplified versions of two other type classes, Ord and Show :
class (Eq a) => Ord a where
(<),(<=),(>=),(>) :: a -> a -> Bool
x < y = not (x >= y)
x <= y = x == y || x < y
x >= y = x == y || x > y
x > y = not (x <= y)
class Show a where
show :: a -> String
The boolean operator (||) denotes disjunction: a || b is true only if at least one of a and b is true. We can define this operator by
(||) :: Bool -> Bool -> Bool
a || b = if a then True else b
The default definitions of the Ord methods are mutually dependent, so one has to provide a specific definition of at least one of them in any instance to break the dependency (unlike Eq where only (/=) was given a default definition). The type class Ord needs Eq as a superclass because it makes use of (==) in the default definitions of the four comparison operations.
The type class Show is used for displaying results. Haskell cannot display the result of a computation unless the type of the result is a member of Show . Let us explain this in a little more detail.
We begin with a mystery:
2.5 Printing values
ghci> "Hello ++"\n"++ "young" ++"\n"++ "lovers"
"Hello\nyoung\nlovers"
Oh. What we wanted was
Hello
young
lovers
Why didn’t Haskell print that?
The reason is that after evaluating a wellformed expression to produce a value, Haskell applies show to the value to produce a string that can be printed at the terminal. Applying show to a value v produces a string that when printed looks exactly like v : Thus,
show 42
= "42"
show 42.3
= "42.3"
show 'a'
= "'a'"
show "hello\n"
= "\"hello\\n\""
Printing the result involves the use of a Haskell command
putStrLn :: String -> IO ()
The type IO a is a special type, the type of input–output computations that when executed have some interaction with the outside world and return a value of type a . If the return value is uninteresting, as with putStrLn , we use the null-tuple value () .
So, Haskell uniformly applies a show-and-put strategy to print values. Since the greeting above is already a string, we really want to miss out the show step and go straight to the put: ghci> putStrLn ("Hello ++"\n"++ "young" ++"\n"++ "lovers")
Hello
young
lovers
Haskell provides many more commands for input–output, for reading and writing to files, for displaying graphics, and so on. Such commands have to be sequencedcorrectly, and for this Haskell provides a special notation, called do -notation. Commands are the subject of Chapter 10 , and what follows is simply a foretaste of things to come.
To see an example, consider the common