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 are, 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.

This also means that a tuple is not a simple type like a primitive (int, char, bool, float, etc). The reason is that, although a tuple is treated as a tuple, it is internally made of distinguishable values. The values can be numbers, characters, strings, objects (from classes), etc. The members of the tuple can also consist of expressions, etc. The items, or members, 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:

The Types of Members of a Tuple

The tuple is the most fundamental collection type in the F# language and we will see other means of creating collections. Most collection types in F# must have the same type of value. The tuple type doesn't follow that rule. Each member of a tuple can be a type different from the other members. Here is an example:

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

In this case, we create a tuple of 5 elements. 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 in the first lesson, F# is an inferred language: the compiler is able to figure out the type of a variable based on the value you assign to it. This also applies to tuples. When you create a tuple, once you specify its members, the compiler applies the appropriate type to each member. Still, if you want, you can indicate the data type of each member. 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 items are of different types, enter the appropriate type of a member in the corresponding placeholder. Here is an example:

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

Individual Variables From a Tuple

As you might 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 items 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 Members of a Tuple

Binding a tuple consists of specifying the names of its members and 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 item will have the first value of the tuple; the second named item 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");

A Placeholder for a Member

Eventually, in your code, you will be able to refer to an item using its name. If you are not planning to refer to a certain member, 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");

Accessing and Using a Tuple

Introduction

A tuple is primarily a list. The primary way you can use it consists of displaying its values to the user. To do this from the printf or the printfn() function, use the %A placeholder. Here is an example:

printfn "%A" ( 1, 4, 6, 12, 36 )

This would produce:

(1, 4, 6, 12, 36)
Press any key to close this window . . .

If the tuple is stored in a variable, use the same %A in the printf or the printfn() function and pass the name of the variable as the second argument. This can be done as follows:

let numbers = (1, 4, 6, 12, 36);
printfn "%A" numbers;

Accessing the Variables 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 using the value in its corresponding position in the tuple. Here are examples:

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

printfn "Student Record"
printfn "Student #:  %d" a
printfn "First Name: %s" b
printfn "Last Name:  %s" c
printfn "Gender:     %c" d

This would produce:

Student Record
Student #:  203814
First Name: Frank
Last Name:  Deuler
Gender:     M
Press any key to close this window . . .

Accessing the Bound Members of a Tuple

If you had bound the members of a tuple, you can access each using its name. Here are examples:

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

printfn "Student 1: %s" student1
printfn "Student 2: %s" student2
printfn "Student 3: %s" student3
printfn "Student 4: %s" student4
printfn "Student 5: %s" student5

This would produce:

Student 1: Frank
Student 2: James
Student 3: Aaron
Student 4: Jennifer
Student 5: Yerimah
Press any key to close this window . . .

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

Tuple Patterns

A tuple pattern is a variable that is in fact a tuple. To create it, use the let keyword followed by a tuple definition. The tuple must be initialized. Here is an example:

let (a, b) = (3, 8);

As done with the other tuples so far, you can access the tuple in a printf or a printfn() function using the %A placeholder. Here is an example:

let (a, b) = (3, 8);

printfn "Point Coordinates: P%A" (a, b)

This would produce:

Point Coordinates: P(3, 8)

Press any key to close this window . . .

One of the characteristics of a tuple is that each of its members is known and can be accessed individually. Here is an example:

let (a, b) = (1, 5);

printf "Point Coordinates: Q(%d, " a;
printf "%d" b;
printfn ")";

This would produce:

Point Coordinates: Q(1, 5)
Press any key to close this window . . .

Tuples and Functions

Introduction

To enhance the behavior of your application, you can create functions, including function that exploit lists. To start, to assist you with tuples and other collections, the F# language provides its own library of classes, functions, and operators. You should be familiar with those functions so that you don't create a function when one exists already.

The First Value of a Pair

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);

printfn "The first value of %A is %d" (5, 73) first;

This would produce:

The first value of (5, 73) is 5
Press any key to close this window . . .

The Second Member of a Pair

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

let second = snd (5, 73);

printfn "The second value of %A is %d" (5, 73) second;

This would produce:

The second value of (5, 73) is 73
Press any key to close this window . . .

Built-In Operators

Introduction

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

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 add(a, b, c) = 
    a + b + c;

let result = add("Pierre ", "Michel ", "Domage")
printfn "Result: %s" result

This would produce:

Result: Pierre Michel Domage
Press any key to close this window . . .

The Subtraction, the Division, and the Multiplication

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 multiply(a, b) = 
    a * b;

let result = multiply(12, 38);
printfn "Result: %d" result;

This would produce:

Result: 456
Press any key to close this window . . .

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 Remainter

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;

let result = modulo(12, 8);
printfn "Modulo of 12 and 8 = %d" result;

This would produce:

Modulo of 12 and 8 = 4
Press any key to close this window . . .

This operator cannot be applied to non-numeric values

The Power of a Number

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;

let result = power(24.48, 5.16);
printfn "Power of 24.48 raised to 5.16 = %.3f" result

This would produce:

Power of 24.48 raised to 5.16 = 14664487.629
Press any key to close this window . . .

This operator can be applied only to decimal numbers

Boolean Operators

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 compare(a, b) = 
    a < b;

let result1 = compare(2, 7);
printfn "The result of 2 < 7 is %A" result1;

let result2 = comparison(15, 8);
printfn "The result of 15 < 8 is %A" result2;

This would produce:

The result of 2 < 7 is true
The result of 15 < 8 is false
Press any key to close this window . . .

Bitwise Operators

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 <<<, >>>, ^^^.

A Tuple As Argument

A Tuple as a Parameter

Remember that 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. Here is an example:

let show (a, b, c, d)

This format is referrred to as tuple form.

After doing this, you can use the tuple or its members in the body of the function. For example, you can use the function to display the values of the individual members of the tuple. Here is an example:

let show (a, b, c, d) =
    printfn "Student Record"
    printfn "Student #:  %d" a
    printfn "First Name: %s" b
    printfn "Last Name:  %s" c
    printfn "Gender:     %c\n" d

show(404842, "Rebeccah", "Benson", 'F');

This would produce:

Student Record
Student #:  404842
First Name: Rebeccah
Last Name:  Benson
Gender:     F

Press any key to close this window . . .

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

let show (a : int, b : string, c : string, d : char) =
    printfn "Student Record"
    printfn "Student #:  %d" a
    printfn "First Name: %s" b
    printfn "Last Name:  %s" c
    printfn "Gender:     %c\n" d

show(404842, "Rebeccah", "Benson", 'F');

Passing Many Tuples

Instead of just one, you can pass as many tuple parameters as you need to a function. 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:

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 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

printfn "Equation: %s" equation

This would produce:

Equation: 7x - y = 11
Press any key to close this window . . .

In the same way, you can pass a combination of (a) tuple(s) and (an)other type(s). Consider the following example:

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

In this case, we are creating a function that is receiving two tuples (one pair and one triple) and one argument of any kind. In reality, when creating a function that takes many arguments, each argument is simply positioned in a placeholder, and each argument can be anything. This means that an argument that is represented with one word can as well be a tuple. Consider the following example:

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

Any one of these arguments 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 an argument 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)

printfn "Gas Utility Company"
printfn "Bill 1: %0.02f" total1
printfn "Bill 2: %0.02f" total2
printfn "Bill 3: %0.02f" total3
printfn "Bill 4: %0.02f" total4
printfn "======================\n"

This would produce:

Gas Utility Company
----------------------
Bill 1: 34.55
Bill 2: 39.97
Bill 3: 30.54
Bill 4: 42.55
======================

Press any key to close this window . . .

When creating the functions, if you want to indicate that an argument 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)
let total2 = prepareBill ((1.3779, 45.50), (0.9607, 84.65), (0.5258, 112.85), 0.2864, "937-405-207",  74.74, "VA")
let total3 = prepareBill ((1.3779, 45.50), (0.9607, 84.65), (0.5258, 112.85), 0.2864, "703-042-581", 106.63, "MD")
let total4 = prepareBill ((1.3779, 45.50), (0.9607, 84.65), (0.5258, 112.85), 0.2864, "402-304-804", 227.37, "DC")

printfn "Gas Utility Company"
printfn "---------------------------"
printfn "Customer Invoice"
printfn "Account #:     %s" customerAccountNumber
printfn "---------------------------"
printfn "Consumption:   122.74"
printfn "Total Charges: %0.02f" total
printfn "State Tax:     1.15"
printfn "---------------------------"
printfn "Amount Due:    %0.02f" (total + 1.15)
printfn "==========================="

This would produce:

Gas Utility Company
---------------------------
Customer Invoice
Account #:     203-840-384
---------------------------
Consumption:   122.74
Total Charges: 35.15
State Tax:     1.15
---------------------------
Amount Due:    36.30
===========================
Press any key to close this window . . .

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) =
    . . .

In the same way, after breaking an element in parts as a tuple, you can use pattern matching to use it. Here is an example:

// let prepareBill (single : (float * float) * (float * float) * (float * float) * float * float) =
let prepareBill single =
    let mutable totalBill = 0.00
    // Breaking the argument in the number of desired parts
    match single with
    | (first, second, third, more, consumption) ->
        match first with // Using each part to get its value
        | (a, b) -> 
            if consumption <= b then
                totalBill <- consumption * a
        match second with
        | (c, d) ->
            if consumption <= d then
                totalBill <- consumption * c
        match third with
        | (e, f) ->
            if consumption <= f then
                totalBill <- consumption * e
            else
                totalBill <- consumption * more
    totalBill
    
let total1 = prepareBill ((0.8275, 28.75), (0.6505, 55.80), (0.4446, 85.65), 0.3258, 22.48)
let total2 = prepareBill ((0.8275, 28.75), (0.6505, 55.80), (0.4446, 85.65), 0.3258, 41.66)
let total3 = prepareBill ((0.8275, 28.75), (0.6505, 55.80), (0.4446, 85.65), 0.3258, 79.46)
let total4 = prepareBill ((0.8275, 28.75), (0.6505, 55.80), (0.4446, 85.65), 0.3258, 97.62)

printfn "Gas Utility Company"
printfn "----------------------"
printfn "Bill 1: %0.02f" total1
printfn "Bill 2: %0.02f" total2
printfn "Bill 3: %0.02f" total3
printfn "Bill 4: %0.02f" total4
printfn "======================"

This would produce:

Gas Utility Company
----------------------
Bill 1: 9.99
Bill 2: 18.52
Bill 3: 35.33
Bill 4: 31.80
======================
Press any key to close this window . . .

Operations on a Tuple

Logical Operators

Instead of one value, you can use a combination of values in pattern matching. The values can be of the same type. Here is an example:

let original  = false // true
let diagnosis = "Positive" // "Negative"

match original, diagnosis with
| true, "Positive" -> printfn "The sick patient was correctly diagnosed as sick"
| false, "Positive" -> printfn "The healthy patient was incorrectly diagnosed as sick"
| true, "Negative" -> printfn "The healthy patient was correctly diagnosed as healthy"
| false, "Negative" -> printfn "The sick patient was incorrectly diagnosed as healthy"
| _ -> ()

This would produce:

The healthy patient was incorrectly diagnosed as sick
Press any key to close this window . . .

The values can also be of different types. Here is an example:

let principal = 12500.00
let compounded = "Yearly"
let periods = 5.00 // years
let mutable interestRate = 0.00

let mutable importance = 0

if principal < 2000.00 then importance <- 1
elif principal < 5000.00 then importance <- 2
elif principal < 10000.00 then importance <- 3
elif principal >= 10000.00 then importance <- 4

match importance, compounded with
| 1, "Daily" -> interestRate <- 3.95 / 100.00
| 1, "Monthly" -> interestRate <- 2.55 / 100.00
| 1, "Yearly" -> interestRate <- 1.95 / 100.00
| 2, "Daily" -> interestRate <- 5.45 / 100.00
| 2, "Monthly" -> interestRate <- 3.85 / 100.00
| 2, "Yearly" -> interestRate <- 3.35 / 100.00
| 3, "Daily" -> interestRate <- 7.45 / 100.00
| 3, "Monthly" -> interestRate <- 6.65 / 100.00
| 3, "Yearly" -> interestRate <- 4.85 / 100.00
| 4, "Daily" -> interestRate <- 9.75 / 100.00
| 4, "Monthly" -> interestRate <- 7.95 / 100.00
| 4, "Yearly" -> interestRate <- 5.85 / 100.00
| _ -> interestRate <- 1.25 / 100.00

let futureValue = principal + (principal * interestRate * periods)

printfn "Investment"
printfn "--------------------------"
printfn "Principal:      %0.0f" principal
printfn "Interest Rate:  %0.02f%c" (interestRate * 100.00) '%'
printfn "Periods:        %0.0f years" periods
printfn "--------------------------"
printfn "Interest Amount: %0.02f" (principal * interestRate * periods)
printfn "Future Value:    %0.02f" futureValue
printfn "=========================="

This would produce:

Investment
--------------------------
Principal:      12500
Interest Rate:  5.85%
Periods:        5 years
--------------------------
Interest Amount: 3656.25
Future Value:    16156.25
==========================
Press any key to close this window . . .

Pattern Matching

Consider the following tuple that we saw earlier:

let numbers = (1, 4, 6, 12, 36);
printfn "%A" numbers;

If you create such a tuple where you don't name the members and simply assign it to a variable, there is no tuple built-in operator to access each member. A solution is use patter matching. To use it, create a matching pattern with one case. The case must be created as a tuple and 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

This would produce:

Numbers: 1, 4, 6, 12, 36
Press any key to close this window . . .

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
        printfn "Number: %d" number

This would produce:

Number: 24
Press any key to close this window . . .

Applying a Pair to a Function

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

Function <|| (Value1, Value2)

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

let powered a b = a ** b;
let result = powered <|| (46.22, 4.37);

printfn "26.22 raised to the power of 2.37 is %.03f" result;

This would produce:

26.22 raised to the power of 2.37 is 18849804.174
Press any key to close this window . . .

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

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 values are in parentheses on the right side of the operator and they are separated by a comma. Here is an example:

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

printfn "Musician: %s" fullName;

This would produce:

Musician: Jean Philippe Marthely
Press any key to close this window . . .

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.

Tuples and the Return Value of a Function

Returning a Value Off a Tuple

A tuple is primarily a value like any other in functional programming. When a tuple is passed to as argument, the function can use the tuple or its items as it sees fit. For example, the function can perform operations on the members of the tuple. Here is an example that takes a tuple as argument, multiplies the members of that tuple and returns the result as a constant value:

let multiply (a, b, c) =
    a * b * c

let result = multiply (15, 24, 48)

printfn "15 * 24 * 48 = %d" result

This would produce:

15 * 24 * 48 = 17280
Press any key to close this window . . .

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 argument and returns a tripple:

let calculate 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, using %A in printf or printfn. Here is an example:

let calculate a =
    (sin a, cos a, tan a);

let result = calculate 45.00
printfn "The sine, the cosine, and the tangent of 45 are: %A\n" result;

This would produce:

The sine, the cosine, and the tangent of 45 are: (0.8509035245, 0.5253219888, 1.619775191)

Press any key to close this window . . .

Of course, a function can receive any number of arguments and return any type of tuple. To consider an example, imagine you want to solve a system of equations in the form:

a1x + b1y = c1
a2x + b2y = c2

Of course, if we know anything about mathematics, it is that there is not a single way to solve such a problem. There are always various ways. For our example, we can solve the first equation by x. That gives us:

                         c1 - b1y
a1x + b1y = c1 => x = ------------
                          a1

We can do the same for the second equation:

                         c2 - b2y
a2x + b2y = c2 => x = ------------
                          a2

We can then equate both values. We get:

        c1 - b1y        c2 - b2y       
 x = ------------ = ------------ 
         a1              a2 

     c1 - b1y      c2 - b2y
=> ----------- = ------------
       a1            a2

=> a2(c1 - b1y) = a1(c2 - b2y)

=> a2c1 - a2b1y = a1c2 - a1b2y

=> a1b2y - a2b1y = a1c2 - a2c1

=> y(a1b2 - a2b1) = a1c2 - a2c1

         a1c2 - a2c1
=> y = ---------------
         a1b2 - a2b1

Now that we have solved y, we can substitute it in the x equation. We get:

                         c1 - b1y
a1x + b1y = c1 => x = ------------
                          a1


                 a1c2 - a2c1              
        c1 - b1---------------     
                 a1b2 - a2b1                
=> x = ------------------------
                  a1          


               a1b1c2 - a2b1c1
        c1 - -------------------    
                 a1b2 - a2b1
     = --------------------------
                     a1               

                     
            a1b2c1 - a2b1c1 - a1b1c2 + a2b1c1
         -------------------------------------- 
                       a1b2 - a2b1
     = ------------------------------------------
                           a1
         -------------------------------------- 
                           1

	  a1b2c1 - a2b1c1 - a1b1c2 + a2b1c1
     = --------------------------------------
                  a1(a1b2 - a2b1)


         a1b2c1 - a2b1c1 - a1b1c2 + a2b1c1
     = -------------------------------------
                  a1a1b2 - a1a2b1

We know that the solution to a system of equations produces two values. This is equivalent to a pair in tuples. So we can pass six values to a function and return a pair. This can be done as follows:

let solveSystemOfEquations a1 b1 c1 a2 b2 c2 =
    let x = (a1*b2*c1 - a2*b1*c1 - a1*b1*c2 + a2*b1*c1) / (a1*a1*b2 - a1*a2*b1);
    let y = (a1*c2 - a2*c1) / (a1*b2 - a2*b1);
    // Return a pair
    (x, y)

let result = solveSystemOfEquations 3 4 -18 2 6 -32;

printfn "Solving: 3x + 4y = -18
         2x + 6y = -32\nproduces %A" result;

This would produce:

Solving: 3x + 4y = -18
         2x + 6y = -32
produces (2, -6)
Press any key to close this window . . .

By the way, you didn't have to declare local variables to solve the problem. The function could have been written as follows:

let solveSystemOfEquations a1 b1 c1 a2 b2 c2 =
    ((a1*b2*c1 - a2*b1*c1 - a1*b1*c2 + a2*b1*c1) / (a1*a1*b2 - a1*a2*b1), (a1*c2 - a2*c1) / (a1*b2 - a2*b1))

let result = solveSystemOfEquations 3 5 2 5 8 3;

printfn "Solving: 3x + 5y = 2
         5x + 8y = 3\nproduces %A" result;

This would produce:

Solving: 3x + 5y = 2
         5x + 8y = 3
produces (-1, 1)
Press any key to close this window . . .

A function can also get a tuple as argument, use it its body, and then return a tuple. Here is an example that takes a pair and returns a pair:

let reverse (a, b) =
    (b, a);

let rv = reverse (24, 36)
printfn "Reversed Pair %A" rv

This would produce:

Reversed Pair (36, 24)
Press any key to close this window . . .

A function can also receive more than one tuple as parameters and return a tuple. Here is an example of a function that takes a tuple and returns a tuple:

let createEquations (a1, b1, c1) (a2, b2, c2) =
    let mutable x1 = ""
    let mutable x2 = ""
    let mutable y1 = ""
    let mutable y2 = ""

    do
        if a1 < -1 then
            x1 <- (string a1) + "x"
        elif a1 = -1 then
            x1 <- "-x"
        elif a1 = 0 then
            x1 <- ""
        elif a1 = 1 then
            x1 <- "x"
        elif a1 > 1 then
            x1 <- (string a1) + "x"
        else
            x1 <- (string a1) + "x"
    
        if b1 < -1 then
            y1 <- "- " + (string (-1 * b1)) + "y"
        elif b1 = -1 then
            y1 <- "- y"
        elif b1 = 0 then
            y1 <- ""
        elif b1 = 1 then
            y1 <- "+ y"
        elif b1 > 1 then
            y1 <- "+ " + (string b1) + "y"
        else
            y1 <- "+ " + (string b1) + "y"

        if a2 < -1 then
            x2 <- (string a2) + "x"
        elif a2 = -1 then
            x2 <- "-x"
        elif a2 = 0 then
            x2 <- ""
        elif a2 = 1 then
            x2 <- "x"
        elif a2 > 1 then
            x2 <- (string a2) + "x"
        else
            x2 <- (string a2) + "x"
    
        if b2 < -1 then
            y2 <- "- " + (string (-1 * b2)) + "y"
        elif b2 = -1 then
            y2 <- "- y"
        elif b2 = 0 then
            y2 <- ""
        elif b2 = 1 then
            y2 <- "+ y"
        elif b2 > 1 then
            y2 <- "+ " + (string b2) + "y"
        else
            y2 <- "+ " + (string b2) + "y"

    (x1 + " " + y1 + " = " + (string c1), x2 + " " + y2 + " = " + (string c2))

let equations = createEquations (1, 1, 6) (-3, 1, 2)
printfn "System of Equations __________"
printfn "   %A" (fst equations)
printfn "   %A" (snd equations)

let (equation1, equation2) = createEquations (3, 2, 19) (1, 1, 8)
printfn "System of Equations __________"
printfn "   %s" equation1
printfn "   %s" equation2

This would produce:

System of Equations __________
   "x + y = 6"
   "-3x + y = 2"
System of Equations __________
   3x + 2y = 19
   x + y = 8
Press any key to close this window . . .

Tuples and Records

A Tuple of Records

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 based on 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 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 using the %A format in a call to printf or printfn. Here is an example:

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")

printfn "Apartment Rental Contract"
printfn "-------------------------"
printfn "Contract Details: %A" contract

This would produce:

Apartment Rental Contract
-------------------------
Contract Details: (10001, {UnitNumber = "102";
         Bedrooms = 1;
         Bathrooms = 1.0;
         SecurityDeposit = 500;
         MonthlyRate = 950;
         Status = NeedsRepair;}, "08/30/2015")

Press any key to close this window . . .

Notice that the result is given in one combination. 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. Here is an example:

printfn "Apartment Rental Contract"
printfn "-------------------------"
match contract with
| (number, apart, startDate) ->
    printfn "Contract #: %i" number
    printfn "Apartment:  %A" apart
    printfn "Rent Start Date: %s" startDate

This would produce:

Apartment Rental Contract
-------------------------
Contract #: 10001
Apartment:  {UnitNumber = "102";
 Bedrooms = 1;
 Bathrooms = 1.0;
 SecurityDeposit = 500;
 MonthlyRate = 950;
 Status = NeedsRepair;}
Rent Start Date: 08/30/2015

Press any key to close this window . . .

Once you get to the record object, you can access its members and use them as you see fit. Here are examples:

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")

printfn "Apartment Rental Contract"
printfn "==========================="
match contract with
| (number, apart, startDate) ->
    printfn "Contract #: %i" number
    printfn "---------------------------"
    printfn "Apartment Details"
    printfn "\tUnit #:    %s" apart.UnitNumber
    printfn "\tBedrooms:  %d" apart.Bedrooms
    printfn "\tBathrooms: %0.02f" apart.Bathrooms
    printfn "\tDeposit:   %d" apart.SecurityDeposit
    printfn "\tRent:      %i/month" apart.MonthlyRate
    printfn "---------------------------"
    printfn "Rent Start Date: %s" startDate

This would produce:

Apartment Rental Contract
===========================
Contract #: 10001
---------------------------
Apartment Details
	Unit #:    102
	Bedrooms:  1
	Bathrooms: 1.00
	Deposit:   500
	Rent:      950/month
---------------------------
Rent Start Date: 08/30/2015

Press any key to close this window . . .

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. 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" }

printfn "Musical Instrument Rental Contract"
printfn "=================================="
printfn "Contract #:      %d" contract.ContractNumber
printfn "Processed by:    %A" contract.ProcessedBy
printfn "Instrument:      %A" contract.MusicalInstrument
printfn "Customer:        %A" contract.Customer
printfn "Rent Start Date: %s" contract.RentStartDate

This would produce:

Musical Instrument Rental Contract
==================================
Contract #:      100001
Processed by:    ("2036-4950", "Joshua Melmann")
Instrument:      (930485, "Roland JUNO-Gi Synthesizer", 1.25)
Customer:        (29374, "Rebecca", "Mewes", 'F')
Rent Start Date: 06/12/2015

Press any key to close this window . . .

Remember that you can use a matching pattern to access each member of a tuple. 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" }

printfn "Musical Instrument Rental Contract"
printfn "=================================================="
printfn "Contract #:      %d" contract.ContractNumber
printf "Processed by:    "
match contract.ProcessedBy with
| (nbr, name) -> printfn "%s(%s)" name nbr
printfn "--------------------------------------------------"
printfn "Instrument"
match contract.MusicalInstrument with
| (x, y, z) ->
    printfn "\tInstrument #: %d" x
    printfn "\tName:         %s" y
    printfn "\tDaily Rate:   %0.02f" z
printfn "--------------------------------------------------"
printfn "Customer"
match contract.Customer with
| (a, b, c, d) ->
    printfn "\tAccount #: %d" a
    printfn "\tFull Name: %s %s" b c
    printf "\tGender:    "
    match d with
    | 'M' -> printfn "Male"
    | 'F' -> printfn "Female"
    | _ -> printfn "Unknown"
printfn "--------------------------------------------------"
printfn "Rent Start Date: %s" contract.RentStartDate

This would produce:

Musical Instrument Rental Contract
==================================================
Contract #:      100001
Processed by:    Joshua Melmann(2036-4950)
--------------------------------------------------
Instrument
	Instrument #: 930485
	Name:         Roland JUNO-Gi Synthesizer
	Daily Rate:   1.25
--------------------------------------------------
Customer
	Account #: 29374
	Full Name: Rebecca Mewes
	Gender:    Female
--------------------------------------------------
Rent Start Date: 06/12/2015

Press any key to close this window . . .

Tuples and Classes

A Tuple of Objects

A member of a tuple can be of any type, including a class or structure. Before getting to a 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))

printfn "Restaurant Order"
printfn "----------------------------"
match order with
| (m, n) -> printfn "Food Order: %A\n" (m.EmployeeNumber, m.FullName, n.ItemCode, n.FoodName, n.UnitPrice)

This would produce:

Restaurant Order
----------------------------
Food Order: (60284, "Frank Evers", "LS01", "Sweet and Sour Chicken", 5.95)

Press any key to close this window . . .

You can create groups for each class by including the appropriate members in individual tuples and access them like that. Here is an example:

printfn "Restaurant Order"
printfn "----------------------------"
match order with
| (m, n) -> printfn "Processed by: %A" (m.EmployeeNumber, m.FullName)
            printfn "Food Ordered: %A" (n.ItemCode, n.FoodName, n.UnitPrice)

Because the class members are identifiable, you can access each by its name and use it as you see fit. Here are examples:

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))

printfn "Restaurant Order"
printfn "----------------------------"
match order with
| (m, n) -> printfn "Processed by: %s(%d)" m.FullName m.EmployeeNumber
            printfn "Food Ordered: %s: %s ($%0.02f)\n" n.ItemCode n.FoodName n.UnitPrice

This would produce:

Restaurant Order
----------------------------
Processed by: Frank Evers(60284)
Food Ordered: LS01: Sweet and Sour Chicken (5.95)

Press any key to close this window . . .

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)

printfn "Restaurant Order"
printfn "----------------------------"
match order with
| (receiptNumber, date, m, n, discount) ->
    printfn "Receipt #:     %i" receiptNumber
    printfn "Order Date:    %s" date
    printfn "Processed by:  %s(%d)" m.FullName m.EmployeeNumber
    printfn "Food Ordered:  %s: %s ($%0.02f)" n.ItemCode n.FoodName n.UnitPrice
    printfn "Discount Rate: %0.02F\n" discount

This would produce:

Restaurant Order
----------------------------
Receipt #:     1001
Order Date:    06/18/2015
Processed by:  Frank Evers(60284)
Food Ordered:  LS01: Sweet and Sour Chicken ($5.95)
Discount Rate: 15.00

Press any key to close this window . . .

Tuples and Methods

When it comes to tuples, the methods of a class primarily follow the same rules of functions. This means that you can pass a tuple to a method. Here is an example:

type HotelRoom(number, roomType, rate) =
    member this.RoomNumber = number
    member this.RoomType = roomType
    member this.DailyRate = rate
    
    // A method with regular parameters
    member this.Describe bed kitchen =
        printfn "Room #:        %d" this.RoomNumber
        printfn "Room Type:     %s" this.RoomType
        if this.RoomType <> "Conference Room" then
            printfn "Bed Type:      %s" bed
        printfn "Kitchen:       %s" kitchen
        printfn "Daily Rate:    %0.02f" this.DailyRate

    // Passing a tuple (triple) to a method
    member this.CalculateInvoice(days, phoneCharge, discount) =
        (float days * rate) + phoneCharge - (float days * rate * discount / 100.00)

let room = HotelRoom(208, "Studio Suite", 125.75)
let days = 5
let phoneUse = 12.48
let total = room.CalculateInvoice(days, phoneUse, 0.00)

printfn "Hotel Room"
printfn "-------------------------------------"
room.Describe "1 Queen Bed" "Full-Size Refrigerator"
printfn "Days:          %d" days
printfn "Phone Charge:  %0.02f" phoneUse
printfn "Total Invoice: %0.02f" total
printfn "-------------------------------------"

This would produce:

Hotel Room
-------------------------------------
Room #:        208
Room Type:     Studio Suite
Bed Type:      1 Queen Bed
Kitchen:       Full-Size Refrigerator
Daily Rate:    125.75
Days:          5
Phone Charge:  12.48
Total Invoice: 641.23
-------------------------------------
Press any key to close this window . . .

In the same way, a method can be made to return a tuple.

Passing a Tuple to a Constructor

At this time, you might have found out 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"))

After creating the object, you can access each tuple and use it. Here is an example:

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

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

printfn "Customer Record"
printfn "-----------------------------"
printfn "Account #: %s" client.AccountNumber
printfn "Full Name: %A" client.FullName
printfn "Emergency Information: %A\n" client.EmergencyInformation

This would produce:

Customer Record
-----------------------------
Account #: 9614-9203
Full Name: ("James", 'D', "Watts")
Emergency Information: ("Frank Watts", "(301) 402-6084")

Press any key to close this window . . .

If you need to access each member of a tuple, remember that you can use a matching tuple. Here is an example:

printfn "Customer Record"
printfn "-----------------------------"
printfn "Account #: %s" client.AccountNumber
match client.FullName with
    | (a, b, c) -> printfn "Full Name: %s %c. %s" a b c
printfn "Emergency Information: %s - %s\n" (fst client.EmergencyInformation) (snd client.EmergencyInformation)

This would produce:

Customer Record
-----------------------------
Account #: 9614-9203
Full Name: James D. Watts
Emergency Information: Frank Watts - (301) 402-6084

Press any key to close this window . . .

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)

printfn "Hotel Room"
printfn "-------------------------------"
printfn "Room #:        %d" room.RoomNumber
printfn "Room Type:     %s" room.RoomType
printfn "Daily Rate:    %0.02f" room.DailyRate
printfn "Days:          %d" days
printfn "Phone Charge:  %0.02f" phoneUse
printfn "Total Invoice: %0.02f" total
printfn "-------------------------------"

This would produce:

Hotel Room
-------------------------------
Room #:        104
Room Type:     Conference Room
Daily Rate:    450.00
Days:          3
Phone Charge:  12.48
Total Invoice: 1092.48
-------------------------------

Press any key to close this window . . .

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 presentInvoice(room : HotelRoom) =
    printfn "Hotel Management - Customer Invoice"
    printfn "-----------------------------------"
    printfn "Room #:        %d" room.RoomNumber
    printfn "Room Type:     %s" room.RoomType
    printfn "Daily Rate:    %0.02f" room.DailyRate
    printfn "Days:          %d" days
    printfn "Phone Charge:  %0.02f" phoneUse
    printfn "Total Invoice: %0.02f" total
    printfn "==================================="
    
presentInvoice room110

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)
presentInvoice room102

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)
presentInvoice room212

This would produce:

Hotel Management - Customer Invoice
-----------------------------------
Room #:        110
Room Type:     Conference Room
Daily Rate:    450.00
Days:          1
Phone Charge:  0.00
Total Invoice: 450.00
===================================
Hotel Management - Customer Invoice
-----------------------------------
Room #:        102
Room Type:     Bedroom
Daily Rate:    95.50
Days:          5
Phone Charge:  7.46
Total Invoice: 484.96
===================================
Hotel Management - Customer Invoice
-----------------------------------
Room #:        212
Room Type:     Bedroom
Daily Rate:    95.50
Days:          3
Phone Charge:  15.68
Total Invoice: 244.88
===================================
Press any key to close this window . . .

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.


Previous Copyright © 2009-2024, FunctionX Saturday 04 November 2023 Next