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]
TrueWhen 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 -> aNum also shows up in the types of integer literals:
Prelude> :t 12
12 :: Num p => pThis 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.0Integral 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 -> aFractional is the class for types that have division. All types that belong to Fractional also belong to Num.
(/) :: Fractional a => a -> a -> aFloating 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 -> aRead 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.0As 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 -> IntThis 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 -> bWe’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') ==> 1We’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.