Part 19

Type Parameters

We introduced type parameters and parametric polymorphism when introducing lists in Lecture 2. Since then, we’ve seen other parameterized types like Maybe and Either. Now we’ll learn how we can define our own parameterized types.

Defining Parameterized Types

The definition for Maybe is:

data Maybe a = Nothing | Just a

What’s a? We define a parameterized type by mentioning a type variable (a in this case) on the left side of the = sign. We can then use the same type variable in fields for our constructors. This is analogous to polymorphic functions. Instead of defining separate functions

headInt :: [Int] -> Int
headBool :: [Bool] -> Bool

and so on, we define one function head :: [a] -> a that works for all types a. Similarly, instead of defining multiple types

data MaybeInt = NothingInt | JustInt Int
data MaybeBool = NothingBool | JustBool Bool

we define one type Maybe a that works for all types a.

Here’s our first own parameterized type Described. The values of type Described a contain a value of type a and a String description.

data Described a = Describe a String

getValue :: Described a -> a
getValue (Describe x _) = x

getDescription :: Described a -> String
getDescription (Describe _ desc) = desc

Prelude> :t Describe
Describe :: a -> String -> Described a
Prelude> :t Describe True "This is true"
Describe True "This is true" :: Described Bool
Prelude> getValue (Describe 3 "a number")
3
Prelude> getDescription (Describe 3 "a number")
"a number"

Syntactic Note

In the above definitions, we’ve used a as a type variable. However any word that starts with a lower case letter is fine. We could have defined Maybe like this:

data Maybe theType = Nothing | Just theType

The rules for Haskell identifiers are:

  • Type variables and names for functions and values start lower case (e.g. a, map, xs)
  • Type names and constructor names start with upper case (e.g. Maybe, Just, Card, Heart)

Note that a type and its constructor can have the same name. This is very common in Haskell code for types that only have one constructor. In this material we try to avoid it to avoid confusion. Here are some examples:

data Pair a = Pair a a
data Report = Report Int String String

Prelude> :t Pair
Pair :: a -> a -> Pair a

Beware of mixing up types and constructors. Luckily types and constructors can never occur in the same context, so you get a nice error:

Prelude> Maybe                              -- trying to use a type name as a value
<interactive>:1:1: error:Data constructor not in scope: Maybe

Prelude> undefined :: Nothing               -- trying to use a constructor as a type
<interactive>:2:14: error:
    Not in scope: type constructor or classNothing

Sidenote: Multiple Type Parameters

Types can have multiple type parameters. The syntax is similar to defining functions with many arguments. Here’s the definition of the standard Either type:

data Either a b = Left a | Right b

Exercises

All exercises can be found in Set5a and Set5b. Please pay attention in the title of the exercise in which file the exercises of this section can be found.

Exercises from 5a:

You have reached the end of this section! Continue to the next section:

You can check your current points from the blue blob in the bottom-right corner of the page.