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 aWhat’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] -> Booland 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 Boolwe 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 theTypeThe 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 aBeware 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 class ‘Nothing’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 bExercises
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 can check your current points from the blue blob in the bottom-right corner of the page.