Introduction to Tuples
Introduction to 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 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:
("Frank", "James")
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");
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 |
|