Home

Tuples

 

Fundamentals of Tuples

 

Introduction

A tuple is a series of values considered as one, as an entity. The tuple is not strictly a data type like an integer or a string, but a tuple is used as if it were. This means that you can declare a variable as a tuple but without specifying that there is such a data type.

 

 

A tuple is not a simple type like a primitive one (int, bool, float, etc). The reason is that, although a tuple is treated as such, it is internally made of distinguishable values. The values can be numbers, characters, strings, objects (from classes), etc. The members, also called elements, of a tuple can also consist of expressions, etc. The items, or members, or elements, of a tuple don't have to be of the same type.

Creating a Tuple

To create a tuple, use the parentheses. Inside the parentheses, list the values separated by commas. Here are examples:

// Integrals
( 1, 4, 6, 12, 36 )
// Characters
( 'b', 'd', 'e', 'g' )
// Strings
( "Aaron", "Jennifer", "Yerimah" )

The items in the tuple can also come from previously declared and initialized variables. Here is an example:

let nbr1 = 16
let nbr2 = 24
let nbr3 = 58

(nbr1, nbr2, nbr3);

Now:

  • If a tuple is made of one element, it is also called a singleton
  • If a tuple is made of two elements, it is called a pair. Here is an example:
    ("Frank", "James");
  • If a tuple is made of three elements, it is called a tripple
  • If a tuple is made of four elements, it can be called a quadruple
  • If a tuple is made of five elements, it can be called a quintuple
  • If a tuple is made of six elements, it is called a sextuple
  • If a tuple is made of seven elements, it is called a septuple
  • If a tuple is made of eight elements, it is called an octuple

The Types of Members of a Tuple

The tuple is the most fundamental collection in F#. As mentioned already, each element of a tuple can be a type different. Here is an example:

(93849, "Anthony Franks", true, 28.85)

In this case, we create a tuple of 5 elements (a quintuple). The first element holds a natural number as the employee number. The second element is a string that is the name of the employee. The third element holds a Boolean value, specifying whether the employee is full-time or not. The last element specifies the hourly salary of the employee.

Naming a Tuple

If you plan to use a tuple many times, you should store it in a variable. When declaring the variable, use the let operator and assign the tuple to it. Here is an example:

let numbers = ( 1, 4, 6, 12, 36 )

As mentioned already, F# is an inferred language: the compiler is able to figure out the type of a value assigned to a variable or when the value is used. This also applies to tuples. When you create a tuple, once you specify its elements, the compiler applies the appropriate type to each member. Still, if you want, you can indicate the data type of each element. To do this, after the name of the tuple, type : followed by the type of each member; the types are separated by *. Here is an example:

let numbers : int * int * int * int * int = ( 1, 4, 6, 12, 36 )

If the elements are of different types, enter the appropriate type of an element in the corresponding placeholder. Here is an example:

let studentInfo : int * string * char = ( 937404, "Bertha Herlin", 'F' )

Individual Variables From a Tuple

As you may have realized, a tuple is a list made of various items. As seen so far, you can create a tuple and store the whole list in one variable. An alternative is to declare various variables but indicate that each gets its value from a tuple. The variables, which means the values in the tuple, can be of different types but the number of variables and the number of elements in the tuple must be the same.

To declare various variables whose values would come from a tuple, separate their names with commas but initialize the group with a tuple. Here is an example:

let a, b, c, d = (203814, "Frank", "Deuler", 'M')

After this declaration, each variable is initialized with the value corresponding to its position in the tuple.

Binding Values to Elements of a Tuple

Binding a tuple consists of specifying the names of its elements by giving a name to each. The formula to follow is:

let (Name1, Name2, Name_X) = (Valu1, Value2, Value_X)

In this case, the first named element will have the first value of the tuple; the second named element will have the second value of the tuple, and so on. Here is an example:

let (student1, student2, student3, student4, student5) = ("Frank", "James", "Aaron", "Jennifer", "Yerimah");

Eventually, in your code, you will be able to refer to an element using its name. If you are not planning to refer to a certain element, you don't have to name it. In this case, you can replace its name with the underscore (_) wildcard or you can put _ in its placeholder. Here are examples:

let (student1, _, student3, _, student5) = ("Frank", "James", "Aaron", "Jennifer", "Yerimah");

Using a Tuple

 

Introduction

The primary way you can use a tuple consists of presenting its values to the user. To do this from the sprintf() function, use the %A placeholder. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise = new Form(MaximizeBox = false,
                        Text = "Tuples",
                        ClientSize = new System.Drawing.Size(210, 64),
                        StartPosition = FormStartPosition.CenterScreen)

let lblNumbers : Label = new Label(AutoSize = true, 
                                   Text = "Numbers:",
                                   Location = new Point(21, 24))
exercise.Controls.Add lblNumbers

let result = sprintf "%A" ( 1, 4, 6, 12, 36 )

let txtNumbers : TextBox = new TextBox(Location = new Point(85, 21),
                                       Text = result,
                                       Size = new System.Drawing.Size(100, 20))
exercise.Controls.Add txtNumbers

do Application.Run exercise   

This would produce:

Fundamentals of Tuples

If the tuple is stored in a variable, you can convert the variable to a string before passing it to a Windows control. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

let exercise = new Form(MaximizeBox = false,
                        Text = "Tuples",
                        ClientSize = new System.Drawing.Size(210, 64),
                        StartPosition = FormStartPosition.CenterScreen)

let lblNumbers : Label = new Label(AutoSize = true, 
                                   Text = "Numbers:",
                                   Location = new Point(21, 24))
exercise.Controls.Add lblNumbers

let numbers = ( 1, 4, 6, 12, 36 )

let txtNumbers : TextBox = new TextBox(Location = new Point(85, 21),
                                       Text = string numbers,
                                       Size = new System.Drawing.Size(100, 20))
exercise.Controls.Add txtNumbers

do Application.Run exercise

Accessing the Elements of a Tuple

We saw earlier that you could declare various variables and initialize them using a tuple. You can then access the value of each variable, by its name, using the value in its corresponding position in the tuple. Here are examples:

open System
open System.Drawing
open System.Windows.Forms

let exercise = new Form(Text = "Date Values",
                        MaximizeBox = false,
                        ClientSize = new System.Drawing.Size(218, 92),
                        StartPosition = FormStartPosition.CenterScreen)

let equation, solution = ("x-4=10", 14)

let lblEquation = new Label(AutoSize = true, 
                            Text = "Equation:", 
                            Location = new Point(23, 20))
exercise.Controls.Add lblEquation
                            
let txtEquation = new TextBox(Text = equation,
                              Location = new Point(90, 17),
                              Size = new System.Drawing.Size(100, 20))
exercise.Controls.Add txtEquation

let lblSolution = new Label(AutoSize = true,
                            Text = "Solution:",
                            Location = new System.Drawing.Point(23, 55))
exercise.Controls.Add lblSolution

let txtSolution = new TextBox(Text = string solution,
                              Location = new Point(90, 52),
                              Size = new System.Drawing.Size(100, 20))
exercise.Controls.Add txtSolution

do Application.Run exercise

This would produce:

Accessing the Elements of a Tuple

If you had bound the elements of a tuple, you can access each using its name. Here is an example:

Author Note

The quick ratio is a business equation that allows a company to find out whether it is currently ready to pay off all its current liabilities based on its current assets and inventory.

open System
open System.Drawing
open System.Windows.Forms

let financialDecisionMaking = new System.Windows.Forms.Form(Text = "Date Values",
                                                            MaximizeBox = false,
                                                            ClientSize = new System.Drawing.Size(218, 110),
                                                            StartPosition = FormStartPosition.CenterScreen)

let (currentAssets, inventory, currentLiatilities) = (4841586.00, 682400.00, 2115351.00)

let lblCurrentAssets = new System.Windows.Forms.Label(AutoSize = true, 
                                                      Text = "Current Assets:", 
                                                      Location = new Point(23, 20))
financialDecisionMaking.Controls.Add(lblCurrentAssets)
                            
let txtCurrentAssets = new System.Windows.Forms.TextBox(Text = string currentAssets,
                                                        Location = new Point(118, 17),
                                                        TextAlign = HorizontalAlignment.Right,
                                                        Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add(txtCurrentAssets)

let lblInventory = new System.Windows.Forms.Label(AutoSize = true,
                                                Text = "Inventory:",
                                                Location = new System.Drawing.Point(23, 46))
financialDecisionMaking.Controls.Add(lblInventory)

let txtInventory = new System.Windows.Forms.TextBox(Text = string inventory,
                                                   Location = new Point(118, 44),
                                                   TextAlign = HorizontalAlignment.Right,
                                                   Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add txtInventory

let lblCurrentLiabilities = new System.Windows.Forms.Label(AutoSize = true, 
                                                           Text = "Current Liabilities:", 
                                                           Location = new Point(23, 74))
financialDecisionMaking.Controls.Add lblCurrentLiabilities
                            
let txtCurrentLiabilities = new System.Windows.Forms.TextBox(Text = string currentAssets,
                                                             Location = new Point(118, 71),
                                                             TextAlign = HorizontalAlignment.Right,
                                                             Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add txtCurrentLiabilities

do System.Windows.Forms.Application.Run financialDecisionMaking

This would produce:

Accessing the Members of a Tuple

Remember that members that were not named cannot be accessed (by their names).

Tuples and Functions

 

Built-In Functions

To let you get the first value of a pair, the F# language provides a function named fst. This function takes a pair as argument. Here is an example:

let first = fst (5, 73)

To find the second member of a pair, you can call the snd() function. Here is an example:

let second = snd (5, 73)

Passing a Tuple as Parameter

So far, if we needed to pass many parameters to a function, we wrote them after the name of the function and we separated them with empty spaces. Here is an example:

let show x y z

Such a format is referred to as curried form. Instead of applying different parameters to a function, you can pass a tuple that would act as a group of values. To do this, in place of one parameter, use a tuple; that is, one or more parameters inclosed in parentheses. Here is an example of a function that takes a pair:

let calculateSalary(cmsRate, sales) = 

This format is referrred to as tuple form. After doing this, you can use the tuple or its elements in the body of the function. For example, you can refer to each parameter by its name and involve it in any statement or expression of your choice. Here is an example:

let calculateSalary(cmsRate, sales) = cmsRate * sales / 100.00

When calling the function, you must pass the tuple; that is, its arguments in parentheses. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

let compoundGrowth = new Form(Text = "Business Mathematics",
                              MaximizeBox = false,
                              ClientSize = new System.Drawing.Size(218, 140),
                              StartPosition = FormStartPosition.CenterScreen)

let lblPrincipal = new Label(AutoSize = true, 
                             Text = "Principal:", 
                             Location = new Point(23, 20))
let txtPrincipal = new TextBox(Location = new Point(118, 17),
                               TextAlign = HorizontalAlignment.Right,
                               Size = new System.Drawing.Size(83, 20))
let lblInterestRate = new Label(AutoSize = true,
                                Text = "Interest Rate:",
                                Location = new System.Drawing.Point(23, 46))
let txtInterestRate = new TextBox(Location = new Point(118, 44),
                                  TextAlign = HorizontalAlignment.Right,
                                  Size = new System.Drawing.Size(83, 20))
let lblPeriods = new Label(AutoSize = true, 
                           Text = "Periods:", 
                           Location = new Point(23, 74))
let txtPeriods = new TextBox(Location = new Point(118, 71),
                             TextAlign = HorizontalAlignment.Right,
                             Size = new System.Drawing.Size(83, 20))
let lblCompounded = new Label(AutoSize = true, 
                              Text = "Compounded:", 
                              Location = new Point(23, 100))
let txtCompounded = new TextBox(Location = new Point(118, 98),
                                Size = new System.Drawing.Size(83, 20))

compoundGrowth.Controls.Add lblPrincipal
compoundGrowth.Controls.Add txtPrincipal
compoundGrowth.Controls.Add lblInterestRate
compoundGrowth.Controls.Add txtInterestRate
compoundGrowth.Controls.Add lblPeriods
compoundGrowth.Controls.Add txtPeriods
compoundGrowth.Controls.Add lblCompounded
compoundGrowth.Controls.Add txtCompounded

let presentLoanDetails(principal, intRate, periods, compounded) =
    txtPrincipal.Text <- string principal
    txtInterestRate.Text <- string (sprintf "%0.02f%s" intRate "%")
    txtPeriods.Text <- string periods
    txtCompounded.Text <- compounded

let formLoader e =
    presentLoanDetails(1500, 12.50, 4, "Monthly")

compoundGrowth.Load.Add formLoader

do System.Windows.Forms.Application.Run compoundGrowth

Here is a test of the program:

Passing a Tuple as Parameter

When passing a tuple to a function, if you want to specify the data type of an element, after its name, type : followed by its type. Here are examples:

let calculateSalary(cmsRate : int, sales : float) = float cmsRate * sales / 100.00

let sales = 80.00
let commissionRate = 25 // %
let commissionEarned = calculateSalary(commissionRate, sales)

let presentLoanDetails(principal : int, intRate : float, periods, compounded : string) =
    txtPrincipal.Text <- string principal
    txtInterestRate.Text <- string (sprintf "%0.02f%s" intRate "%")
    txtPeriods.Text <- string periods
    txtCompounded.Text <- compounded

Passing Many Tuples

Instead of just one, you can pass as many tuple parameters as you need to a function. As done for parameters of primitive types, the tuple parameters are separated by an empty space (not a comma). Here is an example of a function that receives two triple tuples:

let createEquations (a1, b1, c1) (a2, b2, c2) = . . .

In the body of the function, you can then use the parameters as you see fit, and you can return any appropriate value. Here is an example of a function that takes two pairs and returns a string:

open System
open System.Drawing
open System.Windows.Forms

let linearGemotry = new Form(Text = "Linear Geometry",
                             MaximizeBox = false,
                             ClientSize = new System.Drawing.Size(298, 160),
                             StartPosition = FormStartPosition.CenterScreen)

let rec gcd a b =
    if b = 0 then
        a
    else
        gcd b (a % b)

let createEquation (a1, b1) (a2, b2) =
    let a = b1 - b2
    let b = a2 - a1
    let c = (a2 * b1) - (a1 * b2) // (a2 * b1) - (a1 * b1) - (a1 * b1) + (a1 * b2)

    let mutable u = ""
    let mutable v = ""
    let mutable w = ""
    let mutable absu = ""
    let mutable absv = ""
    let mutable absw = ""

    if (a / (gcd a (gcd b c))) = 1 then
        u <- ""
        absu <- ""
    else
        u <- (string (abs (a / (gcd a (gcd b c)))))
        absu <- (string (abs (a / (gcd a (gcd b c)))))

    if (b / (gcd a (gcd b c))) = 1 then
        v <- ""
        absv <- ""
    else
        v <- (string (b / (gcd a (gcd b c))))
        absv <- (string (abs (b / (gcd a (gcd b c)))))

    if (c / (gcd a (gcd b c))) = 1 then
        w <- ""
        absw <- ""
    else
        w <- (string (abs (c / (gcd a (gcd b c)))))
        absw <- (string (abs (c / (gcd a (gcd b c)))))

    if (sign (a / (gcd a (gcd b c))) = -1) && (sign (b / (gcd a (gcd b c))) = 1) then
        if (a / (gcd a (gcd b c))) = -1 then
            "x - " + absv + "y = " + (string ((-1 * c) / (gcd a (gcd b c))))
        else
            absu + "x - " + absv + "y = " + (string ((-1 * c) / (gcd a (gcd b c))))
    else
        u + "x + " + v + "y = " + w

let lblIntroduction = new Label(AutoSize = true, 
                                Text = "Equation of a line that goes through", 
                                Location = new Point(25, 20))
linearGemotry.Controls.Add lblIntroduction
let lblA = new Label(AutoSize = true,
                     Text = "A(",
                     Location = new System.Drawing.Point(22, 54))
linearGemotry.Controls.Add lblA
let txtA1 = new TextBox(Location = new Point(38, 51),
                        TextAlign = HorizontalAlignment.Right,
                        Size = new System.Drawing.Size(36, 20))
linearGemotry.Controls.Add txtA1
let lblComma1 = new Label(AutoSize = true, 
                          Text = ",", 
                          Location = new Point(80, 57))
linearGemotry.Controls.Add lblComma1
let txtB1 = new TextBox(Location = new Point(96, 51),
                        TextAlign = HorizontalAlignment.Right,
                        Size = new System.Drawing.Size(36, 20))
linearGemotry.Controls.Add txtB1
let lblB = new Label(AutoSize = true, 
                     Text = ") and B(:", 
                     Location = new Point(137, 54))
linearGemotry.Controls.Add lblB
let txtA2 = new TextBox(Location = new Point(184, 51),
                        TextAlign = HorizontalAlignment.Right,
                        Size = new System.Drawing.Size(36, 20))
linearGemotry.Controls.Add txtA2
let lblComma2 = new Label(Text = ",", 
                          AutoSize = true, 
                          Location = new Point(223, 57))
linearGemotry.Controls.Add lblComma2
let txtB2 = new TextBox(Location = new Point(239, 51),
                        TextAlign = HorizontalAlignment.Right,
                        Size = new System.Drawing.Size(36, 20))
linearGemotry.Controls.Add txtB2

let btnFind = new Button(Text = "Find",
                         Location = new Point(83, 87),
                         Size = new System.Drawing.Size(135, 23))
linearGemotry.Controls.Add btnFind

let lblEquation = new Label(AutoSize = true,
                            Text = "Equation:",
                            Location = new Point(22, 123))
linearGemotry.Controls.Add lblEquation
let txtEquation = new TextBox(Location = new Point(80, 120),
                              Size = new System.Drawing.Size(138, 20))
linearGemotry.Controls.Add txtEquation

let btnFindClick e =
    let a1 = int txtA1.Text
    let b1 = int txtB1.Text
    let a2 = int txtA2.Text
    let b2 = int txtB2.Text

    let equation = createEquation (a1, b1) (a2, b2)
    txtEquation.Text <- equation

btnFind.Click.Add btnFindClick

do Application.Run linearGemotry

// let equation = createEquation (2, 3) (1, -4); // 7x - y = 11
// let equation = createEquation (-1, 5) (2, -4); // 3x + y = 2
// let equation = createEquation (1, 6) (3, 2); // 2x + y = 8
// let equation = createEquation (1, 3) (0, 1); // 2x - y = -1
// let equation = createEquation (4, 5) (3, 2); // 3x - y = 7
// let equation = createEquation (0, 4) (6, 0); // 2x + 3y = 12
// let equation = createEquation (-2, 3) (3, 8); // x - y = -5
// let equation = createEquation (-3, 3) (3, -1); // 4x + 6y =  6 => Reduced: 2x + 3y = 3
// let equation = createEquation (1, 6) (3, 2);   // 4x + 2y = 16 => Reduced: 2x + y = 8
// let equation = createEquation (3, 2) (7, -4);    // 6x + 4y = 26 => Reduced: 3x + 2y = 13

This would produce:

Passing Many Tuples

Passing Many Tuples

Combining Curried and Tuple Forms

As you know already, a function can take many arguments in curried form. In the same way, a function can take one or more tuples as parameters and each parameter would be a tuple. In this case, each tuple parameter must use its own parantheses that include its elements.

A function can takes parameters in a combination of curried and tuple forms. Each tuple must include its own parentheses while the other parameters would appear without parentheses. Of course, the parameters are separaters only by space. Here is an example:

let calculateCommissionSalary sales (bsCmsRate, bsSales) abvBaseSalesRate = ...

In the body of the function, you can access any parameter, including any element of the tuple parameter, using its name. When calling the function, you must pass the tuple in the same placeholder where it is indicated on the function definition. Here is an example:

let calculateCommissionSalary sales (bsCmsRate, bsSales) abvBaseSalesRate =
    if sales <= bsSales then
        sales * bsCmsRate / 100.00
    else
        let startSales = bsSales * bsCmsRate / 100.00
        let endSales = (sales - bsSales) * abvBaseSalesRate / 100.00
        startSales + endSales

let totalSales = 1200.00
let firstPortionLimit = 800.00
let firstPortionCommissionRate = 25.00
let commissionRateAboveFirstPortion = 10.00
let earnings = calculateCommissionSalary totalSales (firstPortionCommissionRate, firstPortionLimit) commissionRateAboveFirstPortion

In its immense flexibility combined with the fact that it is an infered language, F# allows you to specify any parameters just by its name. Consider the following example:

let calculateCommissionSalary sales commission abvBaseSalesRate =

In this case, each parameter is simply positioned in a placeholder, and each parameter can be anything. This means that a parameter that is represented with one word can as well be a tuple. If a parameter is a tuple, in the body of the function, declare some variables that would each represent a part of the tuple parameter, and assing that parameter to it. You can then use the variables as if they were passed to the function. Here is an example:

let calculateCommissionSalary sales commission abvBaseSalesRate =
    let (bsCmsRate, bsSales) = commission
    
    if sales <= bsSales then
        sales * bsCmsRate / 100.00
    else
        let startSales = bsSales * bsCmsRate / 100.00
        let endSales = (sales - bsSales) * abvBaseSalesRate / 100.00
        startSales + endSales

When calling the function, every parameter that represents a tuple must be passed as such; that is, include the arguments in the parentheses in the place of the tuple parameter, exactly as we did above.

You can pass tuples of different dimensions. You can also pass different types of tuples and regular parameters. Here is an example:

let doSomething (a, b) (d, e, f) something = . . .

In this case, you are creating a function that is receiving two tuples (one pair and one triple) and one parameter of any kind.

Remember that, when creating a function that takes many parameters, each parameter occupies a position and the parameter can be anything. In fact, you can pass many parameters in curried form or one parameter as a tuple and each parameter would represent its own tuple. Consider the following example:

let prepareBill(first, second, third, more, consumption) = . . .

Any one of these parameters can be treated as a tuple in the body of the function. In this example, let's consider "first" as a tuple. In the body of the function, you can declare a variable that is a tuple with names of elements, and initialize that variable with a parameter that is a tuple. You can then use the names of the elements as if they were actual variables. Here is an example of a function that takes three tuples (each a pair) and two floating point values:

let prepareBill(first, second, third, more, consumption) =
    let (a, b) = first
    let (c, d) = second
    let (e, f) = third
    
    if consumption <= b then
        consumption * a
    elif consumption <= d then
        consumption * c
    elif consumption <= f then
        consumption * e
    else
        consumption * more

let total1 = prepareBill ((0.7458, 50.00), (0.5866, 75.00), (0.3274, 105.00), 0.2864, 46.32)
let total2 = prepareBill ((0.7458, 50.00), (0.5866, 75.00), (0.3274, 105.00), 0.2864, 68.14)
let total3 = prepareBill ((0.7458, 50.00), (0.5866, 75.00), (0.3274, 105.00), 0.2864, 93.27)
let total4 = prepareBill ((0.7458, 50.00), (0.5866, 75.00), (0.3274, 105.00), 0.2864, 148.58)

When creating the function, if you want to indicate that a parameter is a tuple, you can specify its data types. To do this, after the name of a parameter, type a colon followed by the types of parameters separated from each other by *. Here are example:

let prepareBill(first : float * float, second : float * float, third : float * float, more, consumption) = . . .

As an alternative, you can put the types in parentheses. Here is an example:

let prepareBill(first : (float * float), second : (float * float), third : (float * float), more, consumption) = . . .

Based on the ability to pass one-word parameters to a function and treat such parameters as tuples, the F# language provides tremendous flexibility. For example, you can pass a single parameter to a function but that parameter can carry as many values as you want, thanks to the features of tuples. Consider the following example:

let prepareBill invoice = . . .

If you pass a parameter that is carrying many internal values, in the body of the function, to segment the parameter in the appropriate individual values, you can first declare a variable for a tuple and initialize that tuple with the parameter. Here is an example:

let prepareBill invoice =
    // Breaking the argument in the number of desired parts
    let (first, second, third, more, consumption) = invoice

From there, you can further segment each member of the new tuple to get the desired values. Here is an example:

let prepareBill invoice =
    // Breaking the argument in the number of desired parts
    let (first, second, third, more, acntBr, consumption, state) = invoice
    // Using each part to get its value
    let (a, b) = first
    let (c, d) = second
    let (e, f) = third
    
    if consumption <= b then
        consumption * a
    elif consumption <= d then
        consumption * c
    elif consumption <= f then
        consumption * e
    else
        consumption * more

let customerAccountNumber = "203-840-384"
let stateResidence = "MD"
let total = prepareBill ((1.3779, 45.50), (0.9607, 84.65), (0.5258, 112.85), 0.2864, customerAccountNumber,  122.74, stateResidence)

Of course, you can specify the data types of the parameters using the appropriate parentheses where necessary. Here is an example:

let prepareBill (invoice : (float * float) * (float * float) * (float * float) * float * string * float * string) =
    . . .

Returning a Value Off a Tuple

When a tuple is passed as parameter, the function can use the tuple or its elements as it sees fit. For example, the function can perform operations on the elements of the tuple and then return the result. Here is an example that takes a tuple as parameter, calculates a new number on the elements of that tuple and returns the result as a constant value:

open System
open System.Drawing
open System.Windows.Forms

let compoundGrowth = new Form(Text = "Business Mathematics",
                              MaximizeBox = false,
                              ClientSize = new System.Drawing.Size(218, 170),
                              StartPosition = FormStartPosition.CenterScreen)

let calculate(principal, payingRate, periods) =
    principal * ((1.00 + (payingRate / periods)) ** (12.00 * periods))

let lblPrincipal = new Label(AutoSize = true, 
                             Text = "Amount to Invest:", 
                             Location = new Point(23, 20))
compoundGrowth.Controls.Add lblPrincipal
let txtPrincipal = new TextBox(Location = new Point(118, 17),
                               Size = new System.Drawing.Size(75, 20))
compoundGrowth.Controls.Add txtPrincipal
let lblPayingRate = new Label(AutoSize = true,
                                Text = "Paying Rate:",
                                Location = new System.Drawing.Point(23, 46))
compoundGrowth.Controls.Add lblPayingRate
let txtPayingRate = new TextBox(Location = new Point(118, 44),
                                  Size = new System.Drawing.Size(60, 20))
compoundGrowth.Controls.Add txtPayingRate
let lblPercentSign = new Label(AutoSize = true, 
                           Text = "%", 
                           Location = new Point(180, 46))
compoundGrowth.Controls.Add lblPercentSign
let lblPeriods = new Label(AutoSize = true, 
                           Text = "Periods:", 
                           Location = new Point(23, 74))
compoundGrowth.Controls.Add lblPeriods
let txtPeriods = new TextBox(Location = new Point(118, 71), Size = new System.Drawing.Size(75, 20))
compoundGrowth.Controls.Add txtPeriods

let btnCalculate = new Button(Text = "Calculate",
                         Location = new Point(118, 98),
                         Size = new System.Drawing.Size(75, 23))

let lblPayingAmount = new Label(AutoSize = true, 
                              Text = "Paying Amount:", 
                              Location = new Point(23, 140))
compoundGrowth.Controls.Add lblPayingAmount)
let txtCompoundedGrowth = new TextBox(Location = new Point(118, 128), Size = new System.Drawing.Size(75, 20))

compoundGrowth.Controls.Add txtCompoundedGrowth

let btnCalculateClick (e : EventArgs) =
    let mutable principal = 0.00
    let mutable rate = 0.00
    let mutable periods = 0.00

    try
        principal <- float txtPrincipal.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the principal is not a valid number", "Compunded Growth",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
    try
        rate <- float txtPayingRate.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the paying rate is not a valid number", "Compunded Growth",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
    try
        periods <- float txtPeriods.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the periods is not a valid number", "Compunded Growth",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;

    let result = calculate(principal, rate, periods)
    txtCompoundedGrowth.Text <- sprintf "%0.02f" result

btnCalculate.Click.Add btnCalculateClick
compoundGrowth.Controls.Add btnCalculate

do System.Windows.Forms.Application.Run compoundGrowth

Remember that you can specify the return type of a function before its = sign. Here is an example:

let calculate(principal, payingRate, periods) : float =
    principal * ((1.00 + (payingRate / periods)) ** (12.00 * periods))

Returning a Tuple

A function can receive regular values, manipulate them, and then return a tuple. Here is an example of a function that gets one value as parameter and returns a triple:

let calculations a =
    let x = sin a;
    let y = cos a;
    let z = tan a;
    (x, y, z);

You can then access the returned type as one value. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

let trigonometry = new Form(Text = "Date Values",
                            MaximizeBox = false,
                            ClientSize = new System.Drawing.Size(528, 55),
                            StartPosition = FormStartPosition.CenterScreen)

let calculate number =
    let x = sin number
    let y = cos number
    let z = tan number
    (x, y, z)

let lblValues = new Label(AutoSize = true, 
                          Text = "(Sine, Cosine, Tangent) of 45.00 =", 
                          Location = new Point(12, 20))
trigonometry.Controls.Add lblValues
                            
let txtValues = new TextBox()
txtValues.Location <- new Point(188, 17)
txtValues.Size <- new System.Drawing.Size(320, 20)

let sct = calculate 45.00
txtValues.Text <- string sct

trigonometry.Controls.Add txtValues

do Application.Run trigonometry

This would produce:

Returning a Tuple

To specify that a function is returning a tuple, before its = sign, type a colon followed by the types of its return tuple. The types must be separated by * from each other. Here is an example:

let calculate number : float * float * float =
    let x = sin number
    let y = cos number
    let z = tan number
    (x, y, z)

Tuples and Function Values

If you create a function that takes one or more function values as arguments, you can make the function return a tuple that holds different values from the function value(s). Here is an example:

let add2Values a b = a + b
let multiply3Values a b c = a * b * c

let calculateInterest (state : float -> float -> float -> float) (totalize : float -> float -> float) printcipal rate periods =
    let totalInterest = state printcipal rate periods
    let futureValue = totalize printcipal totalInterest
    (totalInterest, futureValue)

let interest, future = calculateInterest multiply3Values add2Values 1750.00 (10.25/100.00) 2.00

The body of the function could have the following:

let calculateInterest (state : float -> float -> float -> float) (totalize : float -> float -> float) printcipal rate periods =
    let totalInterest = state printcipal rate periods
    let futureValue = totalize printcipal (state printcipal rate periods)
    (totalInterest, futureValue)

Remember that if you are not planning to use the return value of a function value many times, you don't have to store it first in a variable. You can just call it where it is needed. Here are examples that apply to returning a tuple:

let add2Values a b = a + b
let multiply3Values a b c = a * b * c

let calculateInterest (state : float -> float -> float -> float) (totalize : float -> float -> float) printcipal rate periods =
    (state printcipal rate periods, totalize printcipal (state printcipal rate periods))

let interest, future = calculateInterest multiply3Values add2Values 1750.00 (10.25/100.00) 2.00
     
 

Operations on Tuples

 

Introductory Built-In Operators

To assist you with various types of operations on tuples and their items, the F# language provides a series of operators and built-in functions that can be applied directly to the members of a tuple.

A tuple has built-in functionality to perform all operations using regular algebraic operators:

  • The addition is used to add the members of a tuple. This operation can be performed on numbers or strings. Here is an example:
    let addition(a, b, c) = a + b + c
  • If the members of a tuple are numeric values, you can perform the subtraction (-), the division (/), or the multiplication (*) operation on them. Here is an example that performs the multiplication:
    let multiplication(a, b) = a * b
    If the tuple contains values that don't support the subtraction, the division, or the multiplication, like strings, don't perform that operation. Otherwise you would receive an error
  • The % operator is used to find the remainder of a division of both numbers of a pair. Here is an example:
    let modulo(a, b) = a % b
    This operator cannot be applied to non-numeric values
  • If you have a numeric pair, to find the power of one member raised to the other member, use the ** operator. Here is an example:
    let power(a, b) = a ** b
    This operator can be applied only to decimal numbers
  • The Boolean operators can be applied to two members of a tuple to perform comparisons on them. Remember that the Boolean operators are: =, <, <=, >, >=, and <>. Here is an example:
    let comparison(a, b) = a < b
  • Bit-based operations are available on the members of a tuple. The &&& operator is used to perform the bitwise AND operation on two members of the tuple. Other available operators are <<<, >>>, ^^^.

In the same way, you can perform all types of operations on the members of . Here is an example:

open System
open System.Drawing
open System.Windows.Forms

let financialDecisionMaking = new System.Windows.Forms.Form(Text = "Business",
                                                            MaximizeBox = false,
                                                            ClientSize = new System.Drawing.Size(218, 150),
                                                            StartPosition = FormStartPosition.CenterScreen)

let (currentAssets, inventory, currentLiatilities) = (4841586.00, 682400.00, 2115351.00)

let lblCurrentAssets = new System.Windows.Forms.Label(AutoSize = true, 
                                                      Text = "Current Assets:", 
                                                      Location = new Point(23, 20))
financialDecisionMaking.Controls.Add lblCurrentAssets
                            
let txtCurrentAssets = new System.Windows.Forms.TextBox(Text = string currentAssets,
                                                        Location = new Point(118, 17),
                                                        TextAlign = HorizontalAlignment.Right,
                                                        Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add txtCurrentAssets

let lblInventory = new System.Windows.Forms.Label(AutoSize = true,
                                                Text = "Inventory:",
                                                Location = new System.Drawing.Point(23, 46))
financialDecisionMaking.Controls.Add(lblInventory)

let txtInventory = new System.Windows.Forms.TextBox(Text = string inventory,
                                                   Location = new Point(118, 44),
                                                   TextAlign = HorizontalAlignment.Right,
                                                   Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add txtInventory

let lblCurrentLiabilities = new System.Windows.Forms.Label(AutoSize = true, 
                                                           Text = "Current Liabilities:", 
                                                           Location = new Point(23, 74))
financialDecisionMaking.Controls.Add lblCurrentLiabilities
                            
let txtCurrentLiabilities = new System.Windows.Forms.TextBox(Text = string currentAssets,
                                                             Location = new Point(118, 71),
                                                             TextAlign = HorizontalAlignment.Right,
                                                             Size = new System.Drawing.Size(83, 20))
financialDecisionMaking.Controls.Add txtCurrentLiabilities

let lblLine = new System.Windows.Forms.Label(BackColor = System.Drawing.Color.Black,
                                             Size = new System.Drawing.Size(176, 1),
                                             Location = new System.Drawing.Point(25, 99))
financialDecisionMaking.Controls.Add lblLine

let lblQuickRatio = new System.Windows.Forms.Label(AutoSize = true,
                                                Text = "Quick Ratio:",
                                                Location = new System.Drawing.Point(23, 111))
financialDecisionMaking.Controls.Add lblQuickRatio

let txtQuickRatio = new System.Windows.Forms.TextBox(Location = new Point(118, 109),
                                                   TextAlign = HorizontalAlignment.Right,
                                                   Size = new System.Drawing.Size(83, 20))
txtQuickRatio.Text <- string (sprintf "%0.03f" ((currentAssets - inventory) / currentLiatilities))
                                                   
financialDecisionMaking.Controls.Add txtQuickRatio

do System.Windows.Forms.Application.Run financialDecisionMaking

This would produce:

Operations on Tuples

Applying a Pair to a Function

If you create a function in curried form that takes two parameters, when calling the function, you can pass its arguments as a tuple. This is referred to as applying a tuple to a function.

To apply two values to a function, applying the values as a pair, use the <|| operator. The formula to follow is:

Function <|| (Value1, Value2)

The values are included in parentheses on the right side of the operator. Here is an example:

Author Note

The debt ratio is the relationship between the total liabtilities of a company and the total assets it posses. The debt ratio is dividing the total debt by the total assets.

open System
open System.Drawing
open System.Windows.Forms

let debtRatio = new Form(Text = "Dept Ratio",
                         MaximizeBox = false,
                         ClientSize = new System.Drawing.Size(222, 156),
                         StartPosition = FormStartPosition.CenterScreen)

let calculate debt assets = debt / assets

let lblTotalDebt = new Label(AutoSize = true, 
                             Text = "Total Debt:", 
                             Location = new Point(22, 24))
debtRatio.Controls.Add lblTotalDebt
let txtTotalDebt = new TextBox(Location = new Point(123, 21),
                               Size = new System.Drawing.Size(75, 20))
debtRatio.Controls.Add txtTotalDebt
let lblTotalAssets = new Label(AutoSize = true, 
                             Text = "Total Assets:", 
                             Location = new Point(22, 54))
debtRatio.Controls.Add lblTotalAssets
let txtTotalAssets = new TextBox(Location = new Point(123, 51),
                               Size = new System.Drawing.Size(75, 20))
debtRatio.Controls.Add txtTotalAssets

let btnCalculate = new Button(Text = "Calculate",
                         Location = new Point(123, 82),
                         Size = new System.Drawing.Size(75, 23))
let lblDebtRatio = new Label(AutoSize = true,
                                Text = "Debt Ratio:",
                                Location = new System.Drawing.Point(23, 118))
debtRatio.Controls.Add lblDebtRatio
let txtDebtRatio = new TextBox(Location = new Point(123, 115),
                                  Size = new System.Drawing.Size(75, 20))
debtRatio.Controls.Add txtDebtRatio

let btnCalculateClick (e : EventArgs) =
    let mutable totalDebt = 0.00
    let mutable totalAssets  = 0.00
    
    try
        totalDebt <- float txtTotalDebt.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the total debt is not valid", "Debt Ratio",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
    
    try
        totalAssets <- float txtTotalAssets.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the total assets is not valid", "Debt Ratio",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
                                          
    let result = calculate <|| (totalDebt, totalAssets)
    txtDebtRatio.Text <- sprintf "%0.02f%s" (result * 100.00) "%"

btnCalculate.Click.Add btnCalculateClick
debtRatio.Controls.Add btnCalculate

do System.Windows.Forms.Application.Run debtRatio

This would produce:

Applying a Pair to a Function

You can also apply one value to the left of the function and a pair to the right of the function.

The alternative is to use the ||> in which case the positions of the function and the values in parentheses are inversed. Here is an example:

let btnCalculateClick (e : EventArgs) =
    let mutable totalDebt = 0.00
    let mutable totalAssets  = 0.00
    
    try
        totalDebt <- float txtTotalDebt.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the total debt is not valid", "Debt Ratio",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
    
    try
        totalAssets <- float txtTotalAssets.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the total assets is not valid", "Debt Ratio",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
                                          
    let result = (totalDebt, totalAssets) ||> calculate
    txtDebtRatio.Text <- sprintf "%0.02f%s" (result * 100.00) "%"

Applying a Triple to a Function

To apply three values to a function, use the <||| operator. The formula to use is:

Function <||| (Value1, Value2, Value3)

The function is in curried form and takes three parameters. When calling the function, use the <||| operator but pass the arguments as a triple. Here is an example:

let getFullName a b c = a + " " + b + " " + c
let fullName = getFullName <||| ("Jean", "Philippe", "Marthely")

An alternative is to use the |||> operator. In this case, the values and their parentheses must appear first (to the left of the operator) while the function must appear to the right.

Applying a Tuple to a Function

When studying functions, we saw how you can apply a value to a function. In reality, such a a value can be a tuple. This allows you to apply a single value that happens to hold many sub-values.

Pattern Matching and Tuples

 

Introduction

Consider the following tuple:

let numbers = (1, 4, 6, 12, 36)

If you create such a tuple where you don't name the members and simply assign that tuple to a variable, there is no tuple built-in operator to access each member. A solution is to use pattern matching. To use it, create a matching pattern with one case. The case must have the same number of elements as the tuple. In the tuple, create a name for each element. The name can be a letter or any word that follows the rules for names in F#. The case is followed by -> and what you want to do. From there, you can access each value of the tuple using its corresponding name in the matching case. Here is an example:

let numbers = (1, 4, 6, 12, 36)
match numbers with
    | (one, four, six, twelve, thirtySix) -> printfn "Numbers: %d, %d, %d, %d, %d" one four six twelve thirtySix

Of course, you can consider any of the names in the case as a value and use it any way you want. Here is an example:

let numbers = (1, 4, 6, 12, 36)
match numbers with
    | (one, four, six, twelve, thirtySix) ->
        let number = twelve * 2

Pattern Matching and Parameters

One of the striking features of tuples is that a parameter can be passed with a simple name to a function. That function can treat the parameter as a tuple. As a consequence, a single parameter can carry as many values as possible. In the body of the function, you retrieve values from the parameter. One way you can do this is with pattern matching. This can be done as follows:

let calculate(schedule) =
    match schedule with
    | value1, value2, value3, value4 -> . . .

In the same way, you pass as many parameters as possible and any of them can be treated as a tuple that carries many values. When calling the function, you must provide the appropriate number of values for each parameter. The values of a parameter used as tuple should be passed in their own paratheses. Here is an example:

Author Note

Some companies that sell stocks evaluate the investment by the number of shares that a person buys. When buying, a person is presented with values of different companies or businesses. A typical share has a value. A customer who is interested in the values of a certain company can then purchase a certain number of share. The share principal is calculated by multiplying the number of shares that a person bought by the price per share. The company may use a table named a commission schedule as follows:

Commission Schedule
If the Principal is Between and Pay
0 2499 28.50 + 1.65% of Principal
2500 5999 55.75, 1.05 of Principal
6000 19999 65.85, 0.75 of Principal
20000 49999 80.00, 0.35 of Principal
50000 499999 145.50, 0.15 of Principal
500000 Above 225.00, 0.05 of Principal
 
open System
open System.Drawing
open System.Windows.Forms

let stockTrading = new Form(Text = "Stock Trade",
                              MaximizeBox = false,
                              ClientSize = new System.Drawing.Size(222, 156),
                              StartPosition = FormStartPosition.CenterScreen)

let calculate(schedule1, schedule2, schedule3, schedule4, schedule5, schedule6, shares, price) =
    let principal = shares * price
    let mutable commission = 0.00

    match schedule1 with
    | a1, a2, a3, a4 ->
        if (principal >= a1) && (principal <= a2) then
            commission <- a3 + (principal * a4 / 100.00)
    match schedule2 with
    | b1, b2, b3, b4 ->
        if (principal >= b1) && (principal <= b2) then
            commission <- b3 + (principal * b4 / 100.00)
    match schedule3 with
    | c1, c2, c3, c4 ->
        if (principal >= c1) && (principal <= c2) then
            commission <- c3 + (principal * c4 / 100.00)
    match schedule4 with
    | d1, d2, d3, d4 ->
        if (principal >= d1) && (principal <= d2) then
            commission <- d3 + (principal * d4 / 100.00)
    match schedule5 with
    | e1, e2, e3, e4 ->
        if (principal >= e1) && (principal <= e2) then
            commission <- e3 + (principal * e4 / 100.00)
    match schedule6 with
    | f1, f2, f3 ->
        if principal >= f1 then
            commission <- f2 + (principal * f3 / 100.00)
    principal + commission

let lblNumberOfShares = new Label(AutoSize = true, 
                             Text = "Number of Shares:", 
                             Location = new Point(22, 24))
stockTrading.Controls.Add lblNumberOfShares
let txtNumberOfShares = new TextBox(Location = new Point(123, 21),
                               Size = new System.Drawing.Size(75, 20))
stockTrading.Controls.Add txtNumberOfShares
let lblPricePerShare = new Label(AutoSize = true, 
                             Text = "Price Per Share:", 
                             Location = new Point(22, 54))
stockTrading.Controls.Add lblPricePerShare
let txtPricePerShare = new TextBox(Location = new Point(123, 51),
                               Size = new System.Drawing.Size(75, 20))
stockTrading.Controls.Add txtPricePerShare

let btnCalculate = new Button(Text = "Calculate",
                         Location = new Point(123, 82),
                         Size = new System.Drawing.Size(75, 23))
let lbltotalInvestment = new Label(AutoSize = true,
                                Text = "Total Investment:",
                                Location = new System.Drawing.Point(23, 118))
stockTrading.Controls.Add lbltotalInvestment
let txttotalInvestment = new TextBox(Location = new Point(123, 115),
                                  Size = new System.Drawing.Size(75, 20))
stockTrading.Controls.Add txttotalInvestment

let btnCalculateClick (e : EventArgs) =
    let mutable numberofShares = 0.00
    let mutable pricePerShare  = 0.00
    
    try
        numberofShares <- float txtNumberOfShares.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the number of shares is not correct", "Stock Trade",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
    
    try
        pricePerShare <- float txtPricePerShare.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The value you provided for the price per share is not correct", "Stock Trade",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore;
                                          
    let result = calculate((     0.00,   2499.00,  28.50, 1.65),
                           (  2500.00,   5999.00,  55.75, 1.05),
                           (  6000.00,  19999.00,  65.85, 0.75),
                           ( 20000.00,  49999.00,  80.00, 0.35),
                           ( 50000.00, 499999.00, 145.50, 0.15),
                           (500000.00,            225.00, 0.05),
                           numberofShares, pricePerShare)
    txttotalInvestment.Text <- sprintf "%0.02f" result

btnCalculate.Click.Add btnCalculateClick
stockTrading.Controls.Add btnCalculate

do System.Windows.Forms.Application.Run stockTrading

If. Here is an example:

Pattern Matching and Parameters

Tuples and Records

 

A Tuple of Record Objects

A member of a tuple can be of a record type. Before creating the tuple, you should (must) first create the record type and an object from it. When creating the tuple, add the record object in the placeholder in the parentheses. The combinations are up to you:

  • You can create a tuple that has one or more members based on a record and the other members of primitive types. Here is an example of a tuple whose elements are a natural number, a record object, and a string:
    type OccupancyStatus =
    | Other       = 0
    | Available   = 1
    | Occupied    = 2
    | NeedsRepair = 3
    
    type Apartment = {
        UnitNumber      : string
        Bedrooms        : int
        Bathrooms       : float
        SecurityDeposit : int
        MonthlyRate     : int
        Status          : OccupancyStatus }
    
    let a508293 = { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate =  950; Status = OccupancyStatus.NeedsRepair }
    let contract = (10001, a508293, "08/30#2015")
  • You can create a tuple whose all elements are of the same record. Here is an example:
    type Student = {
        StudentNumber : int
        FirstName     : string
        LastName      : string
        Gender        : char }
    
    let std920817 = {
        StudentNumber = 920817
        FirstName     = "Roland"
        LastName      = "Purcell"
        Gender        = 'M' }
    
    let std274958 = {
        StudentNumber = 274958
        FirstName     = "Josianne"
        LastName      = "Ballam"
        Gender        = 'F' }
    
    let grade5th = (std920817, std274958)
  • You can create a tuple whose elements are a combination of objects of different records. Here is an example:
    type MusicalInstrument = {
        ItemNumber      : int
        ItemName        : string
        MonthlyRent     : float }
    
    type Customer = {
        AccountNumber : int
        CustomerName  : string }
    
    let mi = { ItemNumber = 930485; ItemName = "Roland JUNO-Gi Synthesizer"; MonthlyRent = 28.50 }
    let client = { AccountNumber = 66102; CustomerName = "Jonathan Moella" }
    let rent = (mi, client)
  • You can create a tuple whose elements are combinations of record objects and values of primitive types. Here is an example:
    type MusicalInstrument = {
        ItemNumber      : int
        ItemName        : string
        MonthlyRent     : float }
    
    type Customer = {
        AccountNumber : int
        CustomerName  : string }
    
    let mi = { ItemNumber = 930485; ItemName = "Roland JUNO-Gi Synthesizer"; MonthlyRent = 28.50 }
    let client = { AccountNumber = 66102; CustomerName = "Jonathan Moella" }
    
    let contract = (1001, mi, client, "04/30/2015")

After creating the tuple, you can access it as one object. If you want to access the individual elements of the tuple, you can use a matching pattern whose case would provide a name in the placeholder of each element. Once you get to the record object, you can access its members and use them as you see fit. Here is an example:

open System
open System.Drawing
open System.Windows.Forms

type Customer = {
    AccountNumber : string
    CustomerName  : string
    HomeAddress   : string }

let client = {
    AccountNumber = "2048-5094"
    CustomerName  = "Victorine Barrett"
    HomeAddress   = "14808 Executive Blvd, Rockville, MD 20853" }

let prepareBill(first, second, third, consumption) =
    let (a, b) = first
    let (c, d) = second
    
    if consumption <= b then
        consumption * a
    elif consumption <= d then
        consumption * c
    else
        consumption * third

// Dialog Box: Gas Utility Company - Customer Bill Summary
let gasUtilityCompanyBillPreparation : Form = new Form(MaximizeBox = false,
                                                       MinimizeBox = false,
                                                       Text = "Gas Utility Company",
                                                       FormBorderStyle = FormBorderStyle.FixedDialog,
                                                       ClientSize = new System.Drawing.Size(214, 112),
                                                       StartPosition = FormStartPosition.CenterScreen)

// Label: Account Number
let lblBillPreparationAccountNumber = new Label(AutoSize = true,
                                                Text = "Account #:",
                                                Location = new System.Drawing.Point(20, 16))
gasUtilityCompanyBillPreparation.Controls.Add lblBillPreparationAccountNumber

// Text Box: Account Number
let txtBillPreparationAccountNumber = new TextBox(Size = new System.Drawing.Size(75, 20),
                                                  Location = new System.Drawing.Point(122, 13))
gasUtilityCompanyBillPreparation.Controls.Add txtBillPreparationAccountNumber

// Label: CCF Consumption
let lblBillPreparationCCFConsumption = new Label(AutoSize = true,
                                                 Text = "CCF Consumption:",
                                                 Location = new System.Drawing.Point(22, 45))
gasUtilityCompanyBillPreparation.Controls.Add lblBillPreparationCCFConsumption

// Text Box: CCF Consumption
let txtBillPreparationCCFConsumption = new TextBox(Size = new System.Drawing.Size(75, 20),
                                                   Location = new System.Drawing.Point(122, 42))
gasUtilityCompanyBillPreparation.Controls.Add txtBillPreparationCCFConsumption

// ----------------------------------------------------------------------------------------------
// Form: Gas Utility Company - Customer Bill Summary
let gasUtilityCompany : Form = new Form(MaximizeBox = false,
                                        Text = "Gas Utility Company - Bill Summary",
                                        ClientSize = new System.Drawing.Size(362, 202),
                                        StartPosition = FormStartPosition.CenterScreen)

// Label: Bill Number
let lblBillNumber = new Label(Text = "Bill #:",
                              AutoSize = true,
                              Location = new Point(18, 18))
gasUtilityCompany.Controls.Add lblBillNumber

// Text Box: Bill Number
let txtBillNumber = new TextBox(Size = new System.Drawing.Size(75, 20),
                                Location = new System.Drawing.Point(118, 15))
gasUtilityCompany.Controls.Add txtBillNumber

// Label: Account Number
let lblAccountNumber = new Label(AutoSize = true,
                                 Text = "Account #:",
                                 Location = new System.Drawing.Point(18, 44))
gasUtilityCompany.Controls.Add lblAccountNumber

// Text Box: Account Number
let txtAccountNumber = new TextBox(Size = new System.Drawing.Size(75, 20),
                                   Location = new System.Drawing.Point(118, 44))
gasUtilityCompany.Controls.Add txtAccountNumber

// Label: Customer Name
let lblCustomerName = new Label(AutoSize = true,
                                Text = "Customer Name:",
                                Location = new System.Drawing.Point(18, 70))
gasUtilityCompany.Controls.Add lblCustomerName

// Text Box: Customer Name
let txtCustomerName = new TextBox(Size = new System.Drawing.Size(160, 20),
                                  Location = new System.Drawing.Point(118, 67))
gasUtilityCompany.Controls.Add txtCustomerName

// Label: Home Address
let lblHomeAddress = new Label(AutoSize = true,
                               Text = "Home Address:",
                               Location = new System.Drawing.Point(18, 96))
gasUtilityCompany.Controls.Add lblHomeAddress

// Text Box: Home Address
let txtHomeAddress = new System.Windows.Forms.TextBox(Size = new System.Drawing.Size(224, 20),
                                                      Location = new System.Drawing.Point(118, 96))
gasUtilityCompany.Controls.Add txtHomeAddress
// Label: Line
let lblLine = new Label(BackColor = Color.Black,
                        Location = new System.Drawing.Point(20, 127),
                        Size = new System.Drawing.Size(322, 1))
gasUtilityCompany.Controls.Add lblLine

// Label: CCF Consumption
let lblCCFConsumption = new Label(AutoSize = true,
                                  Text = "CCF Consumption:",
                                  Location = new System.Drawing.Point(18, 144))
gasUtilityCompany.Controls.Add lblCCFConsumption

// Text Box: CCF Consumption
let txtCCFConsumption = new TextBox(Size = new System.Drawing.Size(75, 20),
                                    Location = new System.Drawing.Point(118, 141))
gasUtilityCompany.Controls.Add txtCCFConsumption

// Label: Amount Due
let lblAmountDue = new Label(AutoSize = true,
                             Text = "Amount Due:",
                             Location = new System.Drawing.Point(201, 144))
gasUtilityCompany.Controls.Add lblAmountDue
// Text Box: Amount Due
let txtAmountDue = new TextBox(Location = new Point(277, 141),
                               Size = new System.Drawing.Size(65, 20))
gasUtilityCompany.Controls.Add txtAmountDue

// Button: Close
let btnClose = new Button(Text = "Close",
                          Location = new System.Drawing.Point(267, 172))
let btnCloseClick e = gasUtilityCompany.Close()
btnClose.Click.Add btnCloseClick
gasUtilityCompany.Controls.Add btnClose

let gasUtilityCompanyLoad e =
    gasUtilityCompanyBillPreparation.ShowDialog() |> ignore

// Button: Evaluate
let btnEvaluate = new Button(Text = "Evaluate", Location = new System.Drawing.Point(122, 77))

let btnEvaluateClick e =
    let mutable consumption = 0.00

    if String.IsNullOrEmpty txtBillPreparationAccountNumber.Text then
        MessageBox.Show("You must enter a customer account number", "Gas Utility Company",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore

    if String.IsNullOrEmpty txtBillPreparationCCFConsumption.Text then
        MessageBox.Show("You must enter the amount of gas the customer used", "Gas Utility Company",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore

    let acntNumber = txtBillPreparationAccountNumber.Text

    try
        consumption <- float txtBillPreparationCCFConsumption.Text
        
    with
    | :? FormatException as exc -> MessageBox.Show("The amount of gas consumption you provided is not a valid number", "Gas Utility Company",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore

    if acntNumber = client.AccountNumber then
        let bill = (100001, client, consumption)

        match bill with
        | (nbr, payer, cons) ->
            txtBillNumber.Text <- string nbr
            txtAccountNumber.Text <- payer.AccountNumber
            txtCustomerName.Text <- payer.CustomerName
            txtHomeAddress.Text <- payer.HomeAddress
            txtCCFConsumption.Text <- sprintf "%0.02f" cons

        let amtDue = prepareBill ((0.7458, 50.00), (0.5866, 150.00), 0.3582, consumption)
        txtAmountDue.Text <- sprintf "%0.02f" amtDue

        (* The following would work also
        let (a, b, c) = (100001, client, consumption)

        txtBillNumber.Text <- string a
        
        txtAccountNumber.Text <- b.AccountNumber
        txtCustomerName.Text <- b.CustomerName
        txtHomeAddress.Text <- b.HomeAddress

        txtCCFConsumption.Text <- sprintf "%0.02f" c
        let amtDue = prepareBill ((0.7458, 50.00), (0.6566, 150.00), 0.5824, consumption)
        txtAmountDue.Text <- sprintf "%0.02f" amtDue*)
    else
        MessageBox.Show("There is no customer with that account number", "Gas Utility Company",
                                          MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
    gasUtilityCompanyBillPreparation.Close()

gasUtilityCompany.Load.Add gasUtilityCompanyLoad

btnEvaluate.Click.Add btnEvaluateClick
gasUtilityCompanyBillPreparation.Controls.Add btnEvaluate

[<EntryPoint>]
let main argv = 
    Application.Run gasUtilityCompany
    0 // return an integer exit code

This would produce:

A Tuple of Record Objects

A Tuple of Record Objects

A Tuple in a Record

A member of a record can be a tuple. To create the member, provide its name and specify its data type as a combination of types that are separated by *. Here is an example:

type RentalContract = {
    ContractNumber    : int
    MusicalInstrument : int * string * float }

When creating the object for the record, assign the value of a tuple member as you would for a variable. Here are examples:

type RentalContract = {
    ContractNumber    : int
    ProcessedBy       : string * string
    MusicalInstrument : int * string * float
    Customer          : int * string * string * char
    RentStartDate     : string }

let contract = {
    ContractNumber    = 100001
    ProcessedBy       = ("2036-4950", "Joshua Melmann")
    MusicalInstrument = (930485, "Roland JUNO-Gi Synthesizer", 1.25)
    Customer          = (29374, "Rebecca", "Mewes", 'F')
    RentStartDate     = "06/12/2015" }

You can then access each member of the object. Remember that you can use a matching pattern to access each member of a tuple.

Tuples and Classes

 

A Tuple of Objects

Each member of a tuple can be of any type, including a class or structure. When creating the tuple, you can first create each object. In the tuple, use the name of the object in the desired placeholder. Here is an example:

type Employee(nbr, name) =
    let mutable n = nbr
    let mutable m = name
    member this.EmployeeNumber with get() = n and set(value) = n <- value
    member this.FullName with get() = m and set(value) = m <- value
    
type FoodItem(code, name, price) =
    let mutable cd = code
    let mutable nm = name
    let mutable pr = price
    member this.ItemCode with get() = cd and set(value) = cd <- value
    member this.FoodName with get() = nm and set(value) = nm <- value
    member this.UnitPrice with get() = pr and set(value) = pr <- value

let clerk = Employee(60284, "Frank Evers")
let food = FoodItem("LS01", "Sweet and Sour Chicken", "5.95")

let order = (clerk, food)

You don't have to first create the objects outside the tuple. You can create the objects directly in the tuple. Here is an example:

let order = (Employee(60284, "Frank Evers"), FoodItem("LS01", "Sweet and Sour Chicken", "5.95"))

You can access the members of the tuple as we have done so far. If you want to access each member, you can create a matching pattern. From the option, the first member of the case represents the class of the first element of the tuple. This means that the first member of the case gives you access to the members of the class of the first element. The second element of the case gives you access to the members of the class of the second object, and so on. Here is an example:

type Employee(nbr, name) =
    let mutable n = nbr
    let mutable m = name
    member this.EmployeeNumber with get() = n and set(value) = n <- value
    member this.FullName with get() = m and set(value) = m <- value
    
type FoodItem(code, name, price) =
    let mutable cd = code
    let mutable nm = name
    let mutable pr = price
    member this.ItemCode with get() = cd and set(value) = cd <- value
    member this.FoodName with get() = nm and set(value) = nm <- value
    member this.UnitPrice with get() = pr and set(value) = pr <- value

let order = (Employee(60284, "Frank Evers"), FoodItem("LS01", "Sweet and Sour Chicken", 5.95))

You can create groups for each class by including the appropriate members in individual tuples and access them like that. Because the class members are identifiable, you can access each by its name and use it as you see fit.

In the same way, you can create a tuple that has as many objects as you want, and you can use a combination of objects and values of primitive types in a tuple. If you want to specify the type of each member of the tuple, after the name of the variable, type : followed by the types separated by *. Here is one example:

type Employee(nbr, name) =
    let mutable n = nbr
    let mutable m = name
    member this.EmployeeNumber with get() = n and set(value) = n <- value
    member this.FullName with get() = m and set(value) = m <- value
    
type FoodItem(code, name, price) =
    let mutable cd = code
    let mutable nm = name
    let mutable pr = price
    member this.ItemCode with get() = cd and set(value) = cd <- value
    member this.FoodName with get() = nm and set(value) = nm <- value
    member this.UnitPrice with get() = pr and set(value) = pr <- value

let clerk = Employee(60284, "Frank Evers")
let food = FoodItem("LS01", "Sweet and Sour Chicken", "5.95")

let order : Employee * FoodItem = (clerk, food)

Here is another example:

type Employee(nbr, name) =
    let mutable n = nbr
    let mutable m = name
    member this.EmployeeNumber with get() = n and set(value) = n <- value
    member this.FullName with get() = m and set(value) = m <- value
    
type FoodItem(code, name, price) =
    let mutable cd = code
    let mutable nm = name
    let mutable pr = price
    member this.ItemCode with get() = cd and set(value) = cd <- value
    member this.FoodName with get() = nm and set(value) = nm <- value
    member this.UnitPrice with get() = pr and set(value) = pr <- value

let order : int * string * Employee * FoodItem * float = (1001, "06/18/2015", Employee(60284, "Frank Evers"), FoodItem("LS01", "Sweet and Sour Chicken", 5.95), 15.00)

Returning a Tuple From a Method

A method of a class can return a method when it has performed its action. The method can be passed its own parameter(s) or it can use (a) parameter(s) from a constructor. Here are examples:

open System
open System.Drawing
open System.Windows.Forms

type TimeSheet(salary, mon, tue, wed, thu, fri, sat, sun) =
    let sal = ref salary

    let overtimeSalary = !sal * 1.50
    
    member this.HourlySalary with get() = !sal and set(value) = sal := value

    // Returning a Tuple from a method
    member this.GetMondaySummary() =
        let regTime =
            if mon <= 8.00 then
                mon
            else
                8.00
        let overTime =
            if mon <= 8.00 then 0.00
            else mon - 8.00
        let regPay = regTime * !sal
        let overPay = overTime * overtimeSalary
        (regTime, overTime, regPay, overPay)

    member this.GetTuesdaySummary() =
        let regTime = if tue <= 8.00 then tue else 8.00
        let overTime = if tue <= 8.00 then 0.00 else tue - 8.00
        let regPay = (if tue <= 8.00 then tue else 8.00) * !sal
        let overPay = (if tue <= 8.00 then 0.00 else tue - 8.00) * overtimeSalary
        (regTime, overTime, regPay, overPay)
    member this.GetWednesdaySummary() =
        let regTime = if wed <= 8.00 then wed else 8.00
        let overTime = if wed <= 8.00 then 0.00 else wed - 8.00
        let regPay = (if wed <= 8.00 then wed else 8.00) * !sal
        let overPay = (if wed <= 8.00 then 0.00 else wed - 8.00) * overtimeSalary
        (regTime, overTime, regPay, overPay)
    member this.GetThursdaySummary()  = ((if thu <= 8.00 then thu else 8.00), (if thu <= 8.00 then 0.00 else thu - 8.00), ((if thu <= 8.00 then thu else 8.00) * !sal), ((if thu <= 8.00 then 0.00 else thu - 8.00) * overtimeSalary))
    member this.GetFridaySummary()    = ((if fri <= 8.00 then fri else 8.00), (if fri <= 8.00 then 0.00 else fri - 8.00), ((if fri <= 8.00 then fri else 8.00) * !sal), ((if fri <= 8.00 then 0.00 else fri - 8.00) * overtimeSalary))
    member this.GetSaturdaySummary()  = ((if sat <= 8.00 then sat else 8.00), (if sat <= 8.00 then 0.00 else sat - 8.00), ((if sat <= 8.00 then sat else 8.00) * !sal), ((if sat <= 8.00 then 0.00 else sat - 8.00) * overtimeSalary))
    member this.GetSundaySummary()    = ((if sun <= 8.00 then sun else 8.00), (if sun <= 8.00 then 0.00 else sun - 8.00), ((if sun <= 8.00 then sun else 8.00) * !sal), ((if sun <= 8.00 then 0.00 else sun - 8.00) * overtimeSalary))
                   
// Form: Time Sheet Pay Summary
let timeSheetPaySummary : Form = new Form(ClientSize = new Size(524, 338), MaximizeBox = false, Text = "Time Sheet and Pay Summary", StartPosition = FormStartPosition.CenterScreen)

timeSheetPaySummary.Controls.Add(new Label(Location = new Point(22, 24), AutoSize = true, Text = "Hourly Salary:"))
let txtHourlySalary : TextBox = new TextBox(Location = new Point(102, 21), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.Add txtHourlySalary

timeSheetPaySummary.Controls.Add(new Label(Location = new Point( 99, 57), AutoSize = true, Text = "Monday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(156, 57), AutoSize = true, Text = "Tuesday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(210, 57), AutoSize = true, Text = "Wednesday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(274, 57), AutoSize = true, Text = "Thursday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(329, 57), AutoSize = true, Text = "Friday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(386, 57), AutoSize = true, Text = "Saturday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(441, 57), AutoSize = true, Text = "Sunday"))

let txtTimeSheetMonday    : TextBox = new TextBox(Location = new Point(102, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetTuesday   : TextBox = new TextBox(Location = new Point(159, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetWednesday : TextBox = new TextBox(Location = new Point(216, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetThursday  : TextBox = new TextBox(Location = new Point(273, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetFriday    : TextBox = new TextBox(Location = new Point(330, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetSaturday  : TextBox = new TextBox(Location = new Point(387, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtTimeSheetSunday    : TextBox = new TextBox(Location = new Point(444, 76), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.AddRange([| txtTimeSheetMonday; txtTimeSheetTuesday; txtTimeSheetWednesday; txtTimeSheetThursday; txtTimeSheetFriday; txtTimeSheetSaturday; txtTimeSheetSunday |])

let btnSummarize : Button = new Button(Location = new Point(27, 111), Size = new Size(468, 35), Text = "Summarize")
timeSheetPaySummary.Controls.Add btnSummarize

timeSheetPaySummary.Controls.Add(new Label(Location = new Point( 99, 159), AutoSize = true, Text = "Monday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(156, 159), AutoSize = true, Text = "Tuesday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(210, 159), AutoSize = true, Text = "Wednesday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(274, 159), AutoSize = true, Text = "Thursday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(329, 159), AutoSize = true, Text = "Friday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(386, 159), AutoSize = true, Text = "Saturday"))
timeSheetPaySummary.Controls.Add(new Label(Location = new Point(441, 159), AutoSize = true, Text = "Sunday"))

timeSheetPaySummary.Controls.Add(new Label(Location = new Point(23, 185), AutoSize = true, Text = "Regular Time:"))
let txtSummaryMonRegularTime : TextBox = new TextBox(Location = new Point(102, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryTueRegularTime : TextBox = new TextBox(Location = new Point(159, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryWedRegularTime : TextBox = new TextBox(Location = new Point(216, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryThuRegularTime : TextBox = new TextBox(Location = new Point(273, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryFriRegularTime : TextBox = new TextBox(Location = new Point(330, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySatRegularTime : TextBox = new TextBox(Location = new Point(387, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySunRegularTime : TextBox = new TextBox(Location = new Point(444, 182), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.AddRange([| txtSummaryMonRegularTime; txtSummaryTueRegularTime; txtSummaryWedRegularTime; txtSummaryThuRegularTime; txtSummaryFriRegularTime; txtSummarySatRegularTime; txtSummarySunRegularTime |])

timeSheetPaySummary.Controls.Add(new Label(Location = new Point(23, 211), AutoSize = true, Text = "Overtime:"))
let txtSummaryMonOvertime : TextBox = new TextBox(Location = new Point(102, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryTueOvertime : TextBox = new TextBox(Location = new Point(159, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryWedOvertime : TextBox = new TextBox(Location = new Point(216, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryThuOvertime : TextBox = new TextBox(Location = new Point(273, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryFriOvertime : TextBox = new TextBox(Location = new Point(330, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySatOvertime : TextBox = new TextBox(Location = new Point(387, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySunOvertime : TextBox = new TextBox(Location = new Point(444, 208), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.AddRange([| txtSummaryMonOvertime; txtSummaryTueOvertime; txtSummaryWedOvertime; txtSummaryThuOvertime; txtSummaryFriOvertime; txtSummarySatOvertime; txtSummarySunOvertime|])

timeSheetPaySummary.Controls.Add(new Label(Location = new Point(23, 237), AutoSize = true, Text = "Regular Pay:"))
let txtSummaryMonRegularPay : TextBox = new TextBox(Location = new Point(102, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryTueRegularPay : TextBox = new TextBox(Location = new Point(159, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryWedRegularPay : TextBox = new TextBox(Location = new Point(216, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryThuRegularPay : TextBox = new TextBox(Location = new Point(273, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryFriRegularPay : TextBox = new TextBox(Location = new Point(330, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySatRegularPay : TextBox = new TextBox(Location = new Point(387, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySunRegularPay : TextBox = new TextBox(Location = new Point(444, 234), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.AddRange([| txtSummaryMonRegularPay; txtSummaryTueRegularPay; txtSummaryWedRegularPay; txtSummaryThuRegularPay; txtSummaryFriRegularPay; txtSummarySatRegularPay; txtSummarySunRegularPay |])

timeSheetPaySummary.Controls.Add(new Label(Location = new Point(23, 263), AutoSize = true, Text = "Overtime Pay:"))
let txtSummaryMonOvertimePay : TextBox = new TextBox(Location = new Point(102, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryTueOvertimePay : TextBox = new TextBox(Location = new Point(159, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryWedOvertimePay : TextBox = new TextBox(Location = new Point(216, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryThuOvertimePay : TextBox = new TextBox(Location = new Point(273, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummaryFriOvertimePay : TextBox = new TextBox(Location = new Point(330, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySatOvertimePay : TextBox = new TextBox(Location = new Point(387, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
let txtSummarySunOvertimePay : TextBox = new TextBox(Location = new Point(444, 260), Width = 51, Text = "0.00", TextAlign = HorizontalAlignment.Right)
timeSheetPaySummary.Controls.AddRange([| txtSummaryMonOvertimePay; txtSummaryTueOvertimePay; txtSummaryWedOvertimePay; txtSummaryThuOvertimePay; txtSummaryFriOvertimePay; txtSummarySatOvertimePay; txtSummarySunOvertimePay |])

let btnSummarizeClick e =
    let hourlySalary = float txtHourlySalary.Text
    let mon = float txtTimeSheetMonday.Text
    let tue = float txtTimeSheetTuesday.Text
    let wed = float txtTimeSheetWednesday.Text
    let thu = float txtTimeSheetThursday.Text
    let fri = float txtTimeSheetFriday.Text
    let sat = float txtTimeSheetSaturday.Text
    let sun = float txtTimeSheetSunday.Text

    let ts = new TimeSheet(hourlySalary, mon, tue, wed, thu, fri, sat, sun)
    
    let (monRegTime, monOvertime, monRegPay, monOvertiPay) = ts.GetMondaySummary()
    let (tueRegTime, tueOvertime, tueRegPay, tueOvertiPay) = ts.GetTuesdaySummary()
    let (wedRegTime, wedOvertime, wedRegPay, wedOvertiPay) = ts.GetWednesdaySummary()
    let (thuRegTime, thuOvertime, thuRegPay, thuOvertiPay) = ts.GetThursdaySummary()
    let (friRegTime, friOvertime, friRegPay, friOvertiPay) = ts.GetFridaySummary()
    let (satRegTime, satOvertime, satRegPay, satOvertiPay) = ts.GetSaturdaySummary()
    let (sunRegTime, sunOvertime, sunRegPay, sunOvertiPay) = ts.GetSundaySummary()

    txtSummaryMonRegularTime.Text <- sprintf "%0.02f" monRegTime
    txtSummaryMonOvertime.Text    <- sprintf "%0.02f" monOvertime
    txtSummaryMonRegularPay.Text  <- sprintf "%0.02f" monRegPay
    txtSummaryMonOvertimePay.Text <- sprintf "%0.02f" monOvertiPay

    txtSummaryTueRegularTime.Text <- sprintf "%0.02f" tueRegTime
    txtSummaryTueOvertime.Text    <- sprintf "%0.02f" tueOvertime
    txtSummaryTueRegularPay.Text  <- sprintf "%0.02f" tueRegPay
    txtSummaryTueOvertimePay.Text <- sprintf "%0.02f" tueOvertiPay

    txtSummaryWedRegularTime.Text <- sprintf "%0.02f" wedRegTime
    txtSummaryWedOvertime.Text    <- sprintf "%0.02f" wedOvertime
    txtSummaryWedRegularPay.Text  <- sprintf "%0.02f" wedRegPay
    txtSummaryWedOvertimePay.Text <- sprintf "%0.02f" wedOvertiPay

    txtSummaryThuRegularTime.Text <- sprintf "%0.02f" thuRegTime
    txtSummaryThuOvertime.Text    <- sprintf "%0.02f" thuOvertime
    txtSummaryThuRegularPay.Text  <- sprintf "%0.02f" thuRegPay
    txtSummaryThuOvertimePay.Text <- sprintf "%0.02f" thuOvertiPay

    txtSummaryFriRegularTime.Text <- sprintf "%0.02f" friRegTime
    txtSummaryFriOvertime.Text    <- sprintf "%0.02f" friOvertime
    txtSummaryFriRegularPay.Text  <- sprintf "%0.02f" friRegPay
    txtSummaryFriOvertimePay.Text <- sprintf "%0.02f" friOvertiPay

    txtSummarySatRegularTime.Text <- sprintf "%0.02f" satRegTime
    txtSummarySatOvertime.Text    <- sprintf "%0.02f" satOvertime
    txtSummarySatRegularPay.Text  <- sprintf "%0.02f" satRegPay
    txtSummarySatOvertimePay.Text <- sprintf "%0.02f" satOvertiPay

    txtSummarySunRegularTime.Text <- sprintf "%0.02f" sunRegTime
    txtSummarySunOvertime.Text    <- sprintf "%0.02f" sunOvertime
    txtSummarySunRegularPay.Text  <- sprintf "%0.02f" sunRegPay
    txtSummarySunOvertimePay.Text <- sprintf "%0.02f" sunOvertiPay

btnSummarize.Click.Add btnSummarizeClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(420, 296), Text = "Close")
let btnCloseClick e = timeSheetPaySummary.Close()
btnClose.Click.Add btnCloseClick
timeSheetPaySummary.Controls.Add btnClose

do Application.Run timeSheetPaySummary

Here is an example of executing the program:

Returning a Tuple From a Method

Returning a Tuple From a Method

Passing a Tuple to a Method

Just as seen with functions, an argument passed to a method can be treated as a tuple. When implementing the method, you can just pass a single value. In the body of the method, declare many variables and initialize them as one with the parameter. Then access the members of the tuple and use them any way you want. When calling the method, produce the appropriate number of members of the tuple.

Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

type Employee(emplNbr, fName, lName, salary) =
    member this.EmployeeNumber = emplNbr
    member this.FirstName      = fName
    member this.LastName       = lName
    member this.YearlySalary   = salary

type Payroll(prNbr, emplNbr) =
    let mutable pn : int = prNbr
    let mutable en : string = emplNbr
    member this.PayrollNumber  = prNbr
    member this.EmployeeNumber = emplNbr

    member this.CalculateTotalTime time =
        let mon, tue, wed, thu, fri, sat, sun = time
        mon + tue + wed + thu + fri + sat + sun

let empl = new Employee("92-840", "Martin", "Perhaps", 26.85)
let pay = new Payroll(10001, "92-840")

let totalTime = pay.CalculateTotalTime (8.00, 8.50, 10.00, 8.50, 9.50, 0.00, 0.00)

let payrollPreparation : Form = new Form()
payrollPreparation.MaximizeBox <- false
payrollPreparation.Text <- "Payroll Preparation"
payrollPreparation.ClientSize <- new System.Drawing.Size(264, 86)
payrollPreparation.StartPosition <- FormStartPosition.CenterScreen

// Label: Employee Number
let lblEmployeeNumber = new Label(AutoSize = true, Text = "Employee #:", Location = new Point(21, 18))
payrollPreparation.Controls.Add lblEmployeeNumber

// Text Box: Employee Number
let txtEmployeeNumber = new TextBox(Location = new Point(101, 15), Size = new System.Drawing.Size(62, 20))
payrollPreparation.Controls.Add txtEmployeeNumber

// Button: Find
let btnFind = new Button(Location = new Point(169, 13), Text = "Find Payroll", Width = 85)

// Label: Total Time Worked
let lblTotalTimeWorked = new Label(AutoSize = true, Text = "Time Worked:", Location = new Point(21, 53))
payrollPreparation.Controls.Add lblTotalTimeWorked

// Text Box: Total Time Worked
let txtTotalTimeWorked = new TextBox(Location = new Point(101, 50), Size = new System.Drawing.Size(62, 20))
payrollPreparation.Controls.Add txtTotalTimeWorked

let btnFindClick e =
    if String.IsNullOrEmpty txtEmployeeNumber.Text <> true then
        let emplNbr = txtEmployeeNumber.Text

        if emplNbr = empl.EmployeeNumber then
            txtTotalTimeWorked.Text <- sprintf "%0.02f" totalTime
btnFind.Click.Add btnFindClick

payrollPreparation.Controls.Add btnFind

[<EntryPoint>]
let main argv =
    Application.Run payrollPreparation
    0

Here is an example of running the program:

Tuples and Properties

Remember that you can specify the number of members of the tuple parameter by specifying their types. Here is an example:

type Payroll(prNbr, emplNbr) =
    let mutable pn : int = prNbr
    let mutable en : string = emplNbr
    member this.PayrollNumber  = prNbr
    member this.EmployeeNumber = emplNbr

    member this.CalculateTotalTime (time : float * float * float * float * float * float * float) =
        let mon, tue, wed, thu, fri, sat, sun = time
        mon + tue + wed + thu + fri + sat + sun

Tuples and Properties

A property of a class can be created as a property. Normally, you can just create a property as member variable without specifying its data type. In the body of the class, to use the member as a tuple, you can declare a combination variable and initialize it with the combination with the tuple. You can then use each variable to access the members of the tuple. When creating an object from the class, provide the appropriate tuple as its values in the placeholder of the member. Here is an example:

open System
open System.Drawing
open System.Windows.Forms 

type Employee(emplNbr, fName, lName, salary) =
    member this.EmployeeNumber = emplNbr
    member this.FirstName      = fName
    member this.LastName       = lName
    member this.YearlySalary   = salary

type Payroll(prNbr, emplNbr, time) =
    let mutable pn = prNbr
    let mutable en = emplNbr
    let mutable tm = time
    member this.PayrollNumber  = prNbr
    member this.EmployeeNumber = emplNbr
    member this.TimeWorked     = time
    member this.CalculateTotalTime() =
        let mon, tue, wed, thu, fri, sat, sun = tm
        mon + tue + wed + thu + fri + sat + sun

let empl = new Employee("92-840", "Martin", "Perhaps", 26.85)
let pay = new Payroll(10001, "92-840", (8.00, 8.50, 10.00, 8.50, 9.50, 0.00, 0.00))

let payrollPreparation : Form = new Form()
payrollPreparation.MaximizeBox <- false
payrollPreparation.Text <- "Payroll Preparation"
payrollPreparation.ClientSize <- new System.Drawing.Size(264, 86)
payrollPreparation.StartPosition <- FormStartPosition.CenterScreen

// Label: Employee Number
let lblEmployeeNumber = new Label(AutoSize = true, Text = "Employee #:", Location = new Point(21, 18))
payrollPreparation.Controls.Add lblEmployeeNumber

// Text Box: Employee Number
let txtEmployeeNumber = new TextBox(Location = new Point(101, 15), Size = new System.Drawing.Size(62, 20))
payrollPreparation.Controls.Add txtEmployeeNumber

// Button: Find
let btnFind = new Button(Location = new Point(169, 13), Text = "Find Payroll", Width = 85)

// Label: Total Time Worked
let lblTotalTimeWorked = new Label(AutoSize = true, Text = "Time Worked:", Location = new Point(21, 53))
payrollPreparation.Controls.Add lblTotalTimeWorked

// Text Box: Total Time Worked
let txtTotalTimeWorked = new TextBox(Location = new Point(101, 50), Size = new System.Drawing.Size(62, 20))
payrollPreparation.Controls.Add txtTotalTimeWorked

let btnFindClick e =
    if String.IsNullOrEmpty txtEmployeeNumber.Text <> true then
        let emplNbr = txtEmployeeNumber.Text

        if emplNbr = empl.EmployeeNumber then
            txtTotalTimeWorked.Text <- sprintf "%0.02f" (pay.CalculateTotalTime())
btnFind.Click.Add btnFindClick

payrollPreparation.Controls.Add btnFind

[<EntryPoint>]
let main argv =
    Application.Run payrollPreparation
    0

When creating a property that is a tuple, if you want to indicate that it is a tuple, you can specify the types of its members. To do this, after the name of the mutable member, type a colon and the data type. Separate them with * from each other. Here is an example

type Payroll(prNbr, emplNbr, time) =
    let mutable pn : int = prNbr
    let mutable en : string = emplNbr
    let mutable tm : float * float * float * float * float * float * float = time
    member this.PayrollNumber  = prNbr
    member this.EmployeeNumber = emplNbr
    member this.TimeWorked     = time
    member this.CalculateTotalTime() =
        let mon, tue, wed, thu, fri, sat, sun = tm
        mon + tue + wed + thu + fri + sat + sun

In the same way, you can specify the types of the members of the tuple wherever it is supposed to be used. Here are examples:

type Payroll(prNbr, emplNbr, time : float * float * float * float * float * float * float) =
    let mutable pn : int = prNbr
    let mutable en : string = emplNbr
    let mutable tm : float * float * float * float * float * float * float = time
    member this.PayrollNumber  = prNbr
    member this.EmployeeNumber = emplNbr
    member this.TimeWorked     : float * float * float * float * float * float * float = time
    member this.CalculateTotalTime() =
        let mon, tue, wed, thu, fri, sat, sun = tm
        mon + tue + wed + thu + fri + sat + sun

Passing a Tuple to a Constructor

At this time, you may have found that a constructor doesn't take parameters in a curried form like normal functions or methods do. The parameters passed to a constructor are provided as a tuple. Consider the following constructor:

type Customer(actNbr, name, emrg) =
    let mutable nbr = actNbr
    let mutable name = name
    let mutable emergency = emrg
    member this.AccountNumber with get() = nbr and set(value) = nbr <- value
    member this.FullName with get() = name and set(value) = name <- value
    member this.EmergencyInformation with get() = emergency and set(value) = emergency <- value

Because F# is an inferred language, if you don't specify the type of a parameter, the construtor (or method) may not know the type of value of the parameter until the constructor (oe the method) is called. You can use this feature to pass a tuple to a constructor when creating an object. Here is an example:

let client = Customer("9614-9203", ("James", 'D', "Watts"), ("Frank Watts", "(301) 402-6084"))

If you need to access each member of a tuple, remember that you can use a matching tuple.

Tuples and Named Arguments

When you call a method that takes a tuple, you must provide the values of the tuple in the appropriate order. F# allows you to provide the values in the order of your choice. To do this, when calling the method, in the parentheses, type each parameter name followed by = and its value. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    member this.CalculateInvoice(days, phoneCharge, discount) =
        (float days * rate) + phoneCharge - (float days * rate * discount / 100.00)

let room = HotelRoom(104, "Conference Room", 450.00)
let days = 3
let phoneUse = 12.48
let total = room.CalculateInvoice(phoneCharge = 12.48, days = 3, discount = 20.00)

Method Overloading

By default, you should use unique names for methods in a class. If you try creating two methods with the same name and the exact same signature (in the same class), you would receive an error. Fortunately, there is an alternative. You can provide different versions of the same method in a class. This is referred to as method overloading.

Method overloading consists of having various signatures for the same method. This means that different methods can have the same name but different formats of parameters. One of the methods can be in curreid form and the other(s) take (a) tuple(s). This means that one version can be created like a function that takes parameters separated by spaces. The other versions can each take one or more tuples. Here are examples:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    
    member this.CalculateInvoice days = float days * rate // Curried Form
    member this.CalculateInvoice (days, phoneCharge) =    // Tuple Form: A pair
        (float days * rate) + phoneCharge
    member this.CalculateInvoice (days, phoneCharge, discountRate) = // Tuple Form
        (float days * rate) + phoneCharge - (float days * rate * discountRate / 100.00)

let room110 = HotelRoom(roomType = "Conference Room", rate = 450.00, number = 110)
let mutable days, phoneUse = 1, 0.00
// Calling the version with curried form
let mutable total = room110.CalculateInvoice days

let room102 = HotelRoom(roomType = "Bedroom", rate = 95.50, number = 102)
days <- 5
phoneUse <- 7.46
// Calling the version with a paired tuple form
total <- room102.CalculateInvoice(days, phoneUse)

let room212 = HotelRoom(rate = 95.50, number = 212, roomType = "Bedroom")
days <- 3
phoneUse <- 15.68
// Calling the version with tuple form
total <- room212.CalculateInvoice(days, phoneUse, 20.00)

A Tuple in a Tuple

Each member of a tuple is a placeholder for any type. This means that each element (or the placeholder of an element) can be its own tuple. This allows you to create a tuple in another tuple or to create tuples in a tuple. When doing this, remember that each tuple must use its own parentheses. Here an example of a tuple that contains other tuples:

("529-385", ("Peter", "James", "Watson"), ("Julie watson", "240-144-0285"))

Remember that you can write tuple members on separate lines to make the code easy to read. Here is an example:

(529385,
      ("Peter", "Josh", "Watson"),
      ("Julie watson", "240-144-0285")
    );

As defined in the variable, the primary tuple contains three members. For our example, the first member is an account number and we used one value for it. The second member represents a name; we defined it as a tuple with three members. Our last member represents emergency contact information. We represent it as a tuple with two members (an emergency name and an emergency phone number).

Of course, each tuple can use different types of values.

   
   
 

Home Copyright © 2009-2015, FunctionX Home