Skip to content

Parameterized Types

I already mentioned that many functions in the Haskell standard library are polymorphic or, in more commonly used lingo, generic. This means that they can be applied to arguments of many different types. We express this using type variables. For example, the type of the addition operator was

(+) :: Num a => a -> a -> a

We can add two values of any type a together to produce another value of type a, their sum, as long as a is an instance of the Num type class, that is, as long as a in fact supports arithmetic operations. We'll talk about type classes soon. For now, I want you to focus on the use of type variables to express the idea that the type of a function argument doesn't have to be fixed but can be any type.

When I introduced the concept of type variables, I used Java's ArrayList type as an example that you were hopefully already familiar with. The point I made there is that ArrayList is not a type. ArrayList<String> or ArrayList<Integer> is a type. In order to obtain a concrete kind of an ArrayList, we need to specify the type of the objects we want to store in the ArrayList. ArrayList itself is what we call a parameterized type or a type constructor in Haskell. "Type constructor" because we can view it as a function that takes a type (String or Integer or any other type) as argument and produces a concrete array list type storing elements of this argument type.

It shouldn't come as a surprise that Haskell also allows us to define such type constructors and, given Haskell's focus on reusable code, they are used widely throughout the standard library and in pretty much any sizable Haskell project. Let's look at a few examples.