Learn You a Haskell for Great Good! - Miran Lipovaca [13]
What do you think the type of the head function is? Let’s check with the :t function:
ghci> :t head
head :: [a] -> a
What is this a? Remember that type names start with capital letters, so it can’t be a type. This is actually an example of a type variable, which means that a can be of any type.
Type variables allow functions to operate on values of various types in a type-safe manner. This is a lot like generics in other programming languages. However, Haskell’s version is much more powerful, since it allows us to easily write very general functions.
Functions that use type variables are called polymorphic functions. The type declaration of head states that it takes a list of any type and returns one element of that type.
Note
Although type variables can have names that are longer than one character, we usually give them names like a, b, c, d, and so on.
Remember fst? It returns the first item in a pair. Let’s examine its type:
ghci> :t fst
fst :: (a, b) -> a
You can see that fst takes a tuple and returns an element that is of the same type as its first item. That’s why we can use fst on a pair that contains items of any two types. Note that even though a and b are different type variables, they don’t necessarily need to be different types. This just means that the first item’s type and the return value’s type will be the same.
Type Classes 101
A type class is an interface that defines some behavior. If a type is an instance of a type class, then it supports and implements the behavior the type class describes.
More specifically, a type class specifies a bunch of functions, and when we decide to make a type an instance of a type class, we define what those functions mean for that type.
A type class that defines equality is a good example. The values of many types can be compared for equality by using the == operator. Let’s check the type signature of this operator:
ghci> :t (==)
(==) :: (Eq a) => a -> a -> Bool
Note that the equality operator (==) is actually a function. So are +, *, -, /, and almost every other operator. If a function is composed of only special characters, it’s considered an infix function by default. If we want to examine its type, pass it to another function, or call it as a prefix function, we need to surround it in parentheses, as in the preceding example.
This example shows something new: the => symbol. Everything before this symbol is called a class constraint. We can read this type declaration like this: The equality function takes any two values that are of the same type and returns a Bool. The type of those two values must be an instance of the Eq class.
The Eq type class provides an interface for testing for equality. If it makes sense for two items of a particular type to be compared for equality, then that type can be an instance of the Eq type class. All standard Haskell types (except for input/output types and functions) are instances of Eq.
Note
It’s important to note that type classes are not the same as classes in object-oriented programming languages.
Let’s look at some of the most common Haskell type classes, which enable our types to be easily compared for equality and order, printed as strings, and so on.
The Eq Type Class
As we’ve discussed, Eq is used for types that support equality testing. The functions its instances implement are == and /=. This means that if there’s an Eq class constraint for a type variable in a function, it uses == or /= somewhere inside its definition. When a type implements a function, that means it defines what the function does when used with that particular type. Here are some examples of performing these operations on various instances of Eq:
ghci> 5 == 5
True
ghci> 5 /= 5
False
ghci> 'a' == 'a'
True
ghci> "Ho Ho" == "Ho Ho"
True
ghci> 3.432 == 3.432
True
The Ord Type Class
Ord is a type class for types whose values can