Last time,
I demonstrated the basics of
tuple
types in the
F#
language. However, I (intentionally) failed to answer a couple of important
questions about tuples:
- Once values are bound together in a tuple, how can they be retrieved?
- How are tuples useful?
I'll leave the second question for next time. Today, we'll see how the values
of a tuple can be extracted.
Here is the tuple that we began with
last time:
> let pair = 37, 5;;
val pair = int * int
> pair;;
val it : int * int = (37, 5)
Extracting the values from this tuple is a simple matter of using the fst and
snd
functions (which F# held over from its
ML
heritage). These functions retrieve the first and second values, respectively,
from a two-value tuple.
> fst pair;;
val it : int = 37
> snd pair;;
val it : int = 5
The results of these functions also can be assigned to variables.
> let x = fst pair;;
val x : int
> let y = snd pair;;
val y : int
> printfn "x = %d, y = %d" x y;;
x = 37, y = 5
val it : unit = ()
That's great, but what if we need to extract the values from a tuple whose
length is greater than two?
> let triple = 2, 11, 29;;
val triple : int * int * int
Is there a thrd function we can use to get the last element out of the tuple
above? Nope. In fact, the fst and snd functions that we used on pair won't even
work with this tuple. The problem is that those functions are intended to be used
only with tuples of two values. This becomes clear when their
definitions are considered:
let fst (a,b) = a
let snd (a,b) = b
If we try to use either fst or snd with our triple tuple, a type
mismatch error occurs.
> fst triple;;
fst triple;;
----^^^^^^^
stdin(27,4): error: FS0001: Type mismatch. Expecting a
'a * 'b
but given a
int * int * int.
The tuples have different lengths
stopped due to error
Fortunately, F# provides a very natural syntax to extract the values from any tuple. The idea is to use a simple let statement.
However, instead of binding to a single name, we bind to a pattern made up
of several names. For example, we can extract the values from our triple tuple
like so:
> let x, y, z = triple;;
val x : int
val y : int
val z : int
> printfn "x = %d, y = %d, z = %d" x y z;;
x = 2, y = 11, z = 29
val it : unit = ()
The obvious follow-up question is, what if we only want to retrieve one or two
values from triple?
Put another way, is it really necessary to bind each value of a tuple to a name
even when we aren't interested in all of the values? The answer is, no, it isn't
necessary to bind each value of a tuple of a name. F# provides an ultra-handy
wildcard pattern that trivializes this problem. Wildcards allow us to bind only the
information that we're interested in by adding "holes" to a pattern. In code,
they are represented by an underscore (_) character.
> let x, _, z = triple;;
val x : int
val z : int
> printfn "x = %d, z = %d" x z;;
x = 2, z = 11
val it : unit = ()
Very cool. We'll see more uses of wildcards as this series progresses.
That should answer the first question above. Next time, we'll explore some
important uses of tuples that make them very compelling—especially for .NET developers.