Type variable #
A type variable stands for an underspecified type.
Example. Consider a function
halfthat maps a list to its first half (say rounded down if the list has odd length).The implementation of this function is identical for:
- a list of strings,
- a list of integers,
- a list of Boolean values,
- etc.
A type variable lets us declare such a function
- in Haskell:
half :: [a] -> [a] -- `a` is a type variable here
- or in Java:
/* will be revealed later */
In Haskell #
Syntax. In Haskell, a type variable starts with a lowercase letter (like a regular variable).
By convention, the first letters of the alphabet (
a,b,c, etc.) are often used as type variables.
Examples.
- The type variable
astands for any type,[a]is the type of lists,- a function with type
[a] -> [a]maps a list to a list of the same type,- a function with type
(a, a) -> Boolmaps a pair of elements of the same type to a Boolean value, and its curried version has typea -> a -> Bool.
Example. The Haskell Prelude provides two (partial) functions
headandtail, implemented as follows. Observe the type declarations in these definitions.-- Maps an nonempty list to its head. Throws an error if the list is empty. head :: [a] -> a head (x : _) = x head [] = error "Prelude.head: empty list" -- Maps an nonempty list to its tail. Throws an error if the list is empty. tail :: [a] -> [a] tail (_ : xs) = xs tail [] = error "Prelude.tail: empty list"
Implement the native function composition operator (.) of Haskell, where g . f is the composition of f and g.
(.) :: (b -> c) -> (a -> b) -> a -> c
(g . f) x = g (f x)
Benefits #
Example (continued).
Generality #
The function
headabove can be applied to any nonempty list, regardless of whether it consists of integers, strings, etc.
For instance:
- the expression
head [3,1,2]is valid (and evaluates to3), and- the expression
head ["because","we","can"]is also valid (and evaluates to"because").Type safety #
The type declaration
head :: [a] -> aensures that the following program does not compile:-- auxiliary function even :: Int -> Bool even x = x `mod` 2 == 0 main :: IO () {- Invalid expression: `head ["because","we","can"]` evaluates to a `String`, whereas `even` expects an `Int`. -} main = print $ even (head ["because","we","can"])