Standard Type Classes
Here are some standard Haskell type classes you should know about.
Eq
We already saw the Eq
class for equality comparisons. Here are the basic operations of the Eq
class and some examples of their use. As you can see pretty much all the types we’ve seen so far, except for functions, are members of Eq
.
(==) :: Eq a => a -> a -> Bool
(/=) :: Eq a => a -> a -> Bool
Prelude> 1 == 2
False
Prelude> 1 /= 2
True
Prelude> "Foo" == "Bar"
False
Prelude> [[1,2],[3,4]] == [[1,2],[3,4]]
True
Prelude> (\x -> x+1) == (\x -> x+2)
<interactive>:5:1: error:
• No instance for (Eq (Integer -> Integer))
arising from a use of ‘==’
(maybe you haven't applied a function to enough arguments?)
• In the expression: (\ x -> x + 1) == (\ x -> x + 2)
In an equation for ‘it’: it = (\ x -> x + 1) == (\ x -> x + 2)
There are some other useful functions that use the Eq
class, like nub
from the module Data.List
.
Prelude> import Data.List
Prelude Data.List> :t nub
nub :: Eq a => [a] -> [a]
Prelude Data.List> nub [3,5,3,1,1] -- eliminates duplicates
[3,5,1]
Ord
The Ord
class is for ordering (less than, greater than). Again, here are the basic operations and some examples of their use. Note the new Ordering
type. It has values LT
for “less than”, EQ
for “equal” and GT
for “greater than”.
compare :: Ord a => a -> a -> Ordering
(<) :: Ord a => a -> a -> Bool
(>) :: Ord a => a -> a -> Bool
(>=) :: Ord a => a -> a -> Bool
(<=) :: Ord a => a -> a -> Bool
max :: Ord a => a -> a -> a
min :: Ord a => a -> a -> a
Prelude> compare 1 1 -- 1 is EQual to 1
EQ
Prelude> compare 1 3 -- 1 is Less Than 3
LT
Prelude> compare 1 0 -- 1 is Greater Than 0
GT
Prelude> min 5 3
3
Prelude> max 5 3
5
Prelude> "aardvark" < "banana" -- strings are compared alphabetically
True
Prelude> [1,2,3] > [2,5] -- lists are compared like strings
False
Prelude> [1,2,3] > [1,1]
True
When we can compare values, we can also sort lists of them. The function sort
from Data.List
works on all types that belong to the Ord
class.
Prelude> import Data.List
Prelude Data.List> :t sort
sort :: Ord a => [a] -> [a]
Prelude Data.List> sort [6,1,4,8,2]
[1,2,4,6,8]
Prelude Data.List> sort "black sphinx of quartz, judge my vow!" -- remember, strings are lists!
" !,aabcdefghijklmnoopqrstuuvwxyz"
As a last example, let’s sort a list of lists according to length. We’ll need two helper functions:
-- from the module Data.Ord
-- compares two values "through" the function f
comparing :: (Ord a) => (b -> a) -> b -> b -> Ordering
comparing f x y = compare (f x) (f y)
-- from the module Data.List
-- sorts a list using the given comparison function
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
Now the implementation of sortByLength
is straightforward:
-- sorts lists by their length
sortByLength :: [[a]] -> [[a]]
sortByLength = sortBy (comparing length)
sortByLength [[1,2,3],[4,5],[4,5,6,7]] ==> [[4,5],[1,2,3],[4,5,6,7]]
Num
, Integral
, Fractional
, Floating
The Num
class contains integer arithmetic:
(+) :: Num a => a -> a -> a
(-) :: Num a => a -> a -> a
(*) :: Num a => a -> a -> a
negate :: Num a => a -> a -- 0-x
abs :: Num a => a -> a -- absolute value
signum :: Num a => a -> a -- -1 for negative values, 0 for 0, +1 for positive values
fromInteger :: Num a => Integer -> a
Num
also shows up in the types of integer literals:
Prelude> :t 12
12 :: Num p => p
This means that a literal like 12
can be interpreted as a member of any type implementing Num
. When GHC reads a number literal like, 12
it produces code that corresponds to fromIntegral 12
.
Prelude> 1 :: Int
1
Prelude> 1 :: Double
1.0
Prelude> fromIntegral 1 :: Double
1.0
Integral
is the class of types that represent whole numbers, like Int
and Integer
. The most interesting functions are div
and mod
for integer division and remainder. All types that belong to Integral
also belong to Num
.
div :: Integral a => a -> a -> a
mod :: Integral a => a -> a -> a
Fractional
is the class for types that have division. All types that belong to Fractional
also belong to Num
.
(/) :: Fractional a => a -> a -> a
Floating
contains some additional operations that only make sense for floating point numbers. All types that belong to Floating
also belong to Fractional
(and to Num
).
sqrt :: Floating a => a -> a
sin :: Floating a => a -> a
Read
and Show
The Show
and Read
classes are for the functions show
and read
, that convert values to and from Strings.
show :: Show a => a -> String
read :: Read a => String -> a
Prelude> show 3
"3"
Prelude> read "3" :: Int
3
Prelude> read "3" :: Double
3.0
As you can see above, you often need to use a type annotation with read
so that the compiler can choose the right implementation.
Sidenote: Foldable
One more thing! You might remember that it was mentioned earlier that the type of length
isn’t [a] -> Int
but something more general. Let’s have a look:
Prelude> :t length
length :: Foldable t => t a -> Int
This type looks a bit different than the ones we’ve seen before. The type variable t
has an argument a
. We’ll look at type classes like this in more detail in part 2, but here’s a crash course.
What Foldable
represents is types that you can fold over. The true type of foldr
is:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
We’ve succesfully used the fact that lists are Foldable
since we’ve managed to use length
and foldr
on lists. However, Maybe
is also Foldable
! The Foldable
instance for Maybe
just pretends that values of Maybe a
are like lists of length 0 or 1:
foldr (+) 1 Nothing ==> 1
foldr (+) 1 (Just 3) ==> 4
length Nothing ==> 0
length (Just 'a') ==> 1
We’ll meet some more foldable types next.
Exercises
All exercises can be found in Set4a and Set4b. Please pay attention in the title of the exercise in which file the exercises of this section can be found.
Exercises from 4a:
You can check your current points from the blue blob in the bottom-right corner of the page.