Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

F#6 : Tuples

, 1 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
So our journey into F# continues. The next coupe of posts will be about F# types that may or may not have standard .NET equivalents. This post will be talking about tuples.   What Are Tuples A tuple is a grouping of unnamed but ordered values, possibly of different types.   Creating Tuples Tuples ar

So our journey into F# continues. The next coupe of posts will be about F# types that may or may not have standard .NET equivalents. This post will be talking about tuples.

 

What Are Tuples

A tuple is a grouping of unnamed but ordered values, possibly of different types.

 

Creating Tuples

Tuples are very easy to create, we simply do something like the following. Notice how I have created a mixed bag of tuples here, some are Ints, and others are strings, and we can also mix and match both the types and the number of values

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
//Creating Tuples
let a = (1,2)
let b = (1,"cat")
let c = (1,"cat")
let d = (1,"cat", 'c')

 

Generic Tuples

Functions accepting tuples can accept generic tuples without any issues as well. The F# type inference system will happily deal with deducing the correct types for the tuple. Here is an example

<pre class="brush: csharp; gutter: false; pad-line-numbers: true; title: ; toolbar: false; notranslate">
let someFunction tup = 
    let (x,y) = tup
    printfn "x is %A and y is %A" x y

do someFunction ("cat","dog")
do someFunction (11,12)

And here is the results of running the above, where it can be seen that the someFunction function had no problem accepting and dealing with different typed tuples

image

Tuple Signatures

Up until now we have not touched on understanding F# signatures at all yet, it is in fact a topic i have decided to dedicate a whole blog post too, as I feel it is sufficiently complicated enough to warrant its own blog post. We are however where we are, which is the here and now, and we are exploring tuples, so for  now I just wanted to demonstrate what a tuple signature would look like.

So lets say I had declare the following tuples in a FSI window

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
//Creating Tuples
let a = (1,2)
let b = (1,"codfather")
let c = (1,"c", 12.5)

And then I evaluated them in the FSI window, we would see something like this:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
val a : int * int = (1, 2)
val b : int * string = (1, "codfather")
val c : int * string * float = (1, "c", 12.5)

This is interesting, we can see a couple of things here, namely:

  • The round braces are not part of the type signature
  • The F# type system is able to correctly infer the type based on the values contained in the tuple itself
  • The comma is replaced with a “*”

So just so are crystal clear, a tuple which looks like this

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
let a = (1,2)

Will have type signature of

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
int * int

 

Exploding Tuples

So we have seen how we can create tuples, but what about exploding or deconstructing them back into individual values. Is that possible? Yeah sure it is. As before lets start by looking at some examples:

 

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
//Exploding Tuples
let (a,b) = (1,2)

printfn "(a,b) = (1,2), so value of 'a' should be 1, and it is =%i,\r\n 'b' should be 2, and it is =%i" a b

//using wildcard, essentially dont create an unnessecary value binding if you are
//not interested in it
let (_,z) = (1,2)
printfn "grabbing last value from (1,2) which is = %i" z


//how about some strongly Let bindings
let (a,b :string) = (1,"cat")
printfn "grabbing (1,\"cat\") which has values = %i %s" a b

let (a :int,b :string) = (1,"cat")
printfn "grabbing (1,\"cat\") which has values = %i %s" a b


let (a ,b, c) = (1,"cat", 'c')
printfn "grabbing (1,\"cat\",'c') which has values = %i %s %c" a b c


//using built in helpers
let first = fst (1, 2)
printfn "grabbing fst from (1,2) which has values = %i" first

let second = snd (1, 2)
printfn "grabbing 2nd from (1,2) which has values = %i" second

Where the results are printing to a standard Console window, as follows:

 

image

 

Using Let

So that was the output, but how did we get the individual parts? Well everything you need is in the code above, but lets go through one example. Suppose we had a tuple like this:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
(1,2)

And I wanted to get the values of both the tuple values bound to some new individual values, we could just do this:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
let (a,b) = (1,2)

We can also choose to only grab the values we truly care about, which is done using a wildcard for the unwanted parts. Which makes sure that no unnecessary value binding occurs. Here is an example:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
let (_,z) = (1,2)

Using inbuilt tuple functions

There is also inbuilt support for obtaining the first and second values from a tuple. Which can be done using the “fst” and “snd” functions. There is no support for anything other than the 2st 2 (these are probably the most common cases). “fst” and “2nd” can be used as follows:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
let first = fst (1, 2)
let second = snd (1, 2)

Now I want to draw your attention to a special case, which is when we may have a mismatch with the number of value that we are attempting to explode into individual values. So that would be something like the example here:

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
//oh oh wrong number of values in let binding compiler tells us
let (a ,b) = (1,"cat", 'c')

You can see that the tuple itself actually contains 3 values, but the Let binding only has 2 values, so the compiler warns us about this, as you can see in the screen shot below

image

 

 

 

Creating New Tuples

You may want to create new tuples from existing tuples, this is easy enough, here is an example

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
let oldOne = (1,2)
let (x,y) = oldOne
let newOne = (x+1,y+1)
printfn "original = %A, and we did this (x+1,y+1)\r\n to obtain newOne = %A" oldOne newOne

Which gives this output

image

 

 

Tuple Equality

Tuples are ONLY considered to be equal if

  • They have the same number of values
  • ALL the values are considered equal (Obviously this could include custom Equals methods, or custom IEquatable implementations etc etc)

Lets see some dead simple example shall we.

<pre class="brush: csharp; gutter: false; title: ; toolbar: false; notranslate">
printfn "(1,2) = (3,4) = %b" ((1,2) = (3,4))
printfn "(1,2) = (1,2) = %b" ((1,2) = (1,2))
printfn "('a','b') = ('a','b') = %b" (('a','b') = ('a','b'))
printfn "('a','b') = ('a','c') = %b" (('a','b') = ('a','c'))

which results in this

image

 

In fact if your tuples have different lengths and you are attempting to compare them using the equals operator “=” you will get a warning

image

 

Pattern Matting Tuples

We have not gone into pattern matching yet, but we will see an entire post on this subject later on. For now just know that it is a way to match again input parameters. You can do this against tuples, which is done as follows:

<pre class="brush: csharp; gutter: false; pad-line-numbers: true; title: ; toolbar: false; notranslate">
let someFunction tup = 
    match tup with
    | 1,2 -> printfn "you passed (1,2)"
    | _,_ -> printfn "you passed some other tuple"
    
do someFunction (11,12)
do someFunction (4,5)
do someFunction (1,2)
do someFunction (13,23)

Which gives the following results

image


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
 
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
 
Both of these at Sussex University UK.
 
Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 2 May 2014
Article Copyright 2014 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid