There are a number of ways of producing more complex types out of simpler types. These are some times called compound types.
The first example of that is the list type. As elements of the list all must have the same type, we can specify the type of a list with two pieces of information:
[...]
[False, True, True, True] :: [Bool]
['a', 'b', 'c'] :: [Char] -- Can also be called String
"abc" :: [Char] -- Same as above
["abc", "def"] :: [[Char]] -- Or also [String]
Practice: Write a value of type [[Int]]
.
A tuple is a collection of values separated by commas and surrounded by parentheses. Unlike lists:
Examples:
(False, 3) :: (Bool, Int)
(3, False) :: (Int, Bool) -- This is different from the one above
(True, True, "dat") :: (Bool, Bool, [Char])
() :: () -- The empty tuple, with the empty tuple type
We write functions for tuples by using what is known as pattern-matching:
isBetween :: (Int, Int) -> Int -> Bool
isBetween (a, b) c = a <= c && c <= b
-- Example use: isBetween (2, 5) 3 returns true
What is happening in the example is that the pair (2, 5)
is matched against the pattern (a, b)
and as a result a
is set to 2
and b
is set to 5
. The pair is still considered a single input to the function (thus making two inputs together with the other integer), but it ends up having its parts bound to different variables via the pattern-matching process. We will return to this soon.
We can also mix list types and tuple types. For instance:
[(1, 2), (0, 2), (3, 4)] :: [(Int, Int)] -- A list of pairs of integers
-- A list of pairs of strings and booleans
[("Peter", True), ("Jane", False)] :: [([Char], Bool)]
Write the types we might use to represent the following information:
A function type is written as A -> B
where A
is the type of the input and B
is the type of the output. For example:
add3 x = x + 3 :: Int -> Int
add (x, y) = x + y :: (Int, Int) -> Int
oneUpTo n = [1..n] :: Int -> [Int]
range (a, b) = [a..b] :: (Int, Int) -> [Int]
When writing functions, we tend to declare their type right before their definition, like so:
range :: (Int, Int) -> [Int]
range (a, b) = [a..b]
You may be tempted to think of this function as a function of two variables. It technically is not, and we will discuss this topic on the next section.
Work out the types of the following expressions:
(5 > 3, 3 + head [1, 2, 3])
[length "abc"]
f
defined by f lst = length lst + head lst
g
defined by g lst = if head lst then 5 else 3
Write the types for the following functions: