Tuples (Pairs, Triples, ...)
Remarks#
-
Haskell does not support tuples with one component natively.
-
Units (written
()
) can be understood as tuples with zero components. -
There are no predefined functions to extract components of tuples with more than two components. If you feel that you need such functions, consider using a custom data type with record labels instead of the tuple type. Then you can use the record labels as functions to extract the components.
Construct tuple values
Use parentheses and commas to create tuples. Use one comma to create a pair.
(1, 2)
Use more commas to create tuples with more components.
(1, 2, 3)
(1, 2, 3, 4)
Note that it is also possible to declare tuples using in their unsugared form.
(,) 1 2 -- equivalent to (1,2)
(,,) 1 2 3 -- equivalent to (1,2,3)
Tuples can contain values of different types.
("answer", 42, '?')
Tuples can contain complex values such as lists or more tuples.
([1, 2, 3], "hello", ('A', 65))
(1, (2, (3, 4), 5), 6)
Write tuple types
Use parentheses and commas to write tuple types. Use one comma to write a pair type.
(Int, Int)
Use more commas to write tuple types with more components.
(Int, Int, Int)
(Int, Int, Int, Int)
Tuples can contain values of different types.
(String, Int, Char)
Tuples can contain complex values such as lists or more tuples.
([Int], String, (Char, Int))
(Int, (Int, (Int, Int), Int), Int)
Pattern Match on Tuples
Pattern matching on tuples uses the tuple constructors. To match a pair for example, we’d use the (,)
constructor:
myFunction1 (a, b) = ...
We use more commas to match tuples with more components:
myFunction2 (a, b, c) = ...
myFunction3 (a, b, c, d) = ...
Tuple patterns can contain complex patterns such as list patterns or more tuple patterns.
myFunction4 ([a, b, c], d, e) = ...
myFunction5 (a, (b, (c, d), e), f) = ...
Extract tuple components
Use the fst
and snd
functions (from Prelude
or Data.Tuple
) to extract the first and second component of pairs.
fst (1, 2) -- evaluates to 1
snd (1, 2) -- evaluates to 2
Or use pattern matching.
case (1, 2) of (result, _) => result -- evaluates to 1
case (1, 2) of (_, result) => result -- evaluates to 2
Pattern matching also works for tuples with more than two components.
case (1, 2, 3) of (result, _, _) => result -- evaluates to 1
case (1, 2, 3) of (_, result, _) => result -- evaluates to 2
case (1, 2, 3) of (_, _, result) => result -- evaluates to 3
Haskell does not provide standard functions like fst
or snd
for tuples with more than two components. The tuple
library on Hackage provides such functions in the Data.Tuple.Select
module.
Apply a binary function to a tuple (uncurrying)
Use the uncurry
function (from Prelude
or Data.Tuple
) to convert a binary function to a function on tuples.
uncurry (+) (1, 2) -- computes 3
uncurry map (negate, [1, 2, 3]) -- computes [-1, -2, -3]
uncurry uncurry ((+), (1, 2)) -- computes 3
map (uncurry (+)) [(1, 2), (3, 4), (5, 6)] -- computes [3, 7, 11]
uncurry (curry f) -- computes the same as f
Apply a tuple function to two arguments (currying)
Use the curry
function (from Prelude
or Data.Tuple
) to convert a function that takes tuples to a function that takes two arguments.
curry fst 1 2 -- computes 1
curry snd 1 2 -- computes 2
curry (uncurry f) -- computes the same as f
import Data.Tuple (swap)
curry swap 1 2 -- computes (2, 1)
Swap pair components
Use swap
(from Data.Tuple
) to swap the components of a pair.
import Data.Tuple (swap)
swap (1, 2) -- evaluates to (2, 1)
Or use pattern matching.
case (1, 2) of (x, y) => (y, x) -- evaluates to (2, 1)
Strictness of matching a tuple
The pattern (p1, p2)
is strict in the outermost tuple constructor, which can lead to unexpected strictness behaviour. For example, the following expression diverges (using Data.Function.fix
):
fix $ \(x, y) -> (1, 2)
since the match on (x, y)
is strict in the tuple constructor. However, the following expression, using an irrefutable pattern, evaluates to (1, 2)
as expected:
fix $ \ ~(x, y) -> (1, 2)