After initializing a record, one way you can use it consists of presenting its values to the user. To do this, use the printfn() function and specify %A as the value placeholder. Here is an example: type Country = { Continent: string Name : string Capital : string Area : uint32 InternetCode: string } let Ecuador = { Continent = "South America" Name = "Ecuador" Capital = "Quito" Area = 283561u InternetCode = "ec" } printfn "%A" Ecuador This would produce: {Continent = "South America"; Name = "Ecuador"; Capital = "Quito"; Area = 283561u; InternetCode = "ec";} Press any key to continue . . .
To access a label of a record, type the name of the variable you declared, followed by a period, followed by the label you want. Here are examples: type Student = { ID : int FirstName : string LastName : string Gender : char } let std = { ID = 773946 FirstName = "Amir" LastName = "Shalloub" Gender = 'M' } printfn "Student Information"; printfn "Student ID: %d" std.ID; printfn "First Name: %s" std.FirstName; printfn "Last Name: %s" std.LastName; printfn "Gender: %c" std.Gender; This would produce: Student Information Student ID: 773946 First Name: Amir Last Name: Shalloub Gender: M Press any key to continue . . . Remember that, if you are using two or more records that have the same labels, to identify a member, you should qualify it in the curly brackets of the variable. Here are examples: type Student = {
ID : int
FirstName : string
LastName : string
Gender : char
}
type Employee = {
ID : int
FirstName : string
LastName : string
Gender : char
}
let std = {
Student.ID = 773946
FirstName = "Amir"
LastName = "Shalloub"
Gender = 'M'
}
let contractor = {
ID = 50225
Employee.FirstName = "Hellie"
LastName = "Pastore"
Gender = 'F'
}
printfn "Student Information";
printfn "Student ID: %d" std.ID;
printfn "First Name: %s" std.FirstName;
printfn "Last Name: %s" std.LastName;
printfn "Gender: %c" std.Gender;
printfn "=----------------------="
printfn "Employee Record";
printfn "Employee ID: %d" contractor.ID;
printfn "First Name: %s" contractor.FirstName;
printfn "Last Name: %s" contractor.LastName;
printfn "Gender: %c" contractor.Gender;
This would produce: Student Information Student ID: 773946 First Name: Amir Last Name: Shalloub Gender: M =----------------------= Employee Record Employee ID: 50225 First Name: Hellie Last Name: Pastore Gender: F Press any key to continue . . .
After creating an object from a record, you may want to create another object whose some labels use the same values as some labels of the previous objects. In this case, you can copy the similar values. To do this, in the {} of the new object, type the name of the object followed by with, the name of the label whose value you want to change and assign the desired value to it. Here is an example: type Apartment = {
UnitNumber : string
Bedrooms : int
Bathrooms : float
SecurityDeposit : int
MonthlyRate : int }
let a508293 = { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate = 950 }
let a729397 = { a508293 with UnitNumber = "103" }
printfn "Apartment: %A" a508293
printfn "Apartment: %A" a729397
This would produce: Apartment: {UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 950;} Apartment: {UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 950;} Press any key to continue . . . Notice that the second object gets all its values from the object copied, except for the label whose value was changed. In the same way, you can change the value of any of the labels that are different from the copied object. Here are examples: type Apartment = { UnitNumber : string Bedrooms : int Bathrooms : float SecurityDeposit : int MonthlyRate : int } let a399475 = { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150 } let a508293 = { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate = 950 } let a729397 = { a508293 with UnitNumber = "103" } let a809387 = { UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.00; SecurityDeposit = 850; MonthlyRate = 1350 } let a486360 = { a508293 with UnitNumber = "105"; MonthlyRate = 1050 } let a273004 = { a399475 with UnitNumber = "106"; Bathrooms = 1.00; MonthlyRate = 1050 } printfn "Apartment: %A" a399475 printfn "Apartment: %A" a508293 printfn "Apartment: %A" a729397 printfn "Apartment: %A" a809387 printfn "Apartment: %A" a486360 printfn "Apartment: %A" a273004 This would produce: Apartment: {UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.0; SecurityDeposit = 650; MonthlyRate = 1150;} Apartment: {UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 950;} Apartment: {UnitNumber = "103"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 950;} Apartment: {UnitNumber = "104"; Bedrooms = 3; Bathrooms = 2.0; SecurityDeposit = 850; MonthlyRate = 1350;} Apartment: {UnitNumber = "105"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 1050;} Apartment: {UnitNumber = "106"; Bedrooms = 2; Bathrooms = 1.0; SecurityDeposit = 650; MonthlyRate = 1050;} Press any key to continue . . .
By default, after creating an object, you cannot change the values of its labels. If you want to create a label whose value can change, you must create it as mutable. Here is an example: type Apartment = {
UnitNumber : string
Bedrooms : int
Bathrooms : float
SecurityDeposit : int
mutable MonthlyRate : int }
Before using it, first create an object based on the record. To change the value of the field, type the name of the object, a period, and the name of the field. Then assign the desired value to it, using the <- operator. Here are examples: type Apartment = {
UnitNumber : string
Bedrooms : int
Bathrooms : float
SecurityDeposit : int
mutable MonthlyRate : int }
let a399475 = { UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.00; SecurityDeposit = 650; MonthlyRate = 1150 }
let a508293 = { UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.00; SecurityDeposit = 500; MonthlyRate = 950 }
printfn "Apartment: %A" a399475
printfn "Apartment: %A" a508293
a399475.MonthlyRate <- 1075
a508293.MonthlyRate <- 1025
printfn "\nThe monthly rent has changed\n"
printfn "The new tenant will get a discount"
printfn "Apartment: %A" a399475
printfn "The new tenant will see an increase in rent"
printfn "Apartment: %A" a508293
This would produce: Apartment: {UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.0; SecurityDeposit = 650; MonthlyRate = 1150;} Apartment: {UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 950;} The monthly rent has changed The new tenant will get a discount Apartment: {UnitNumber = "101"; Bedrooms = 2; Bathrooms = 2.0; SecurityDeposit = 650; MonthlyRate = 1075;} The new tenant will see an increase in rent Apartment: {UnitNumber = "102"; Bedrooms = 1; Bathrooms = 1.0; SecurityDeposit = 500; MonthlyRate = 1025;} Press any key to continue . . .
A record can be passed as argument to a function. To do this, include the argument in parentheses and specify the name of the record as data type. Here is an example: let describe (road : RoadSystem) = . . . In the body of the function, you can access each member of the record by applying the period operator on the argument followed by the desired member of the record. Here is an example: type RoadSystem = {
RoadName : string
Distance : float
Location : string }
let describe (road : RoadSystem) =
printfn "Road System Database"
printfn "=----------------------------------------------------="
printfn "Road Name: %s" road.RoadName
printfn "Distance: %0.2f miles" road.Distance
printfn "Location: %s\n" road.Location
let USRoute1 =
{
RoadName = "U.S. Route 1"; Distance = 2369.00;
Location = "From FortKent, Maine To Key West, Florida"
}
describe USRoute1
This would produce: Road System Database =----------------------------------------------------= Road Name: U.S. Route 1 Distance: 2369.00 miles Location: From FortKent, Maine To Key West, Florida Press any key to continue . . . Inside the function, besides accessing it, you can use or manipulate the record in any appropriate and allowed way. Here is an example that checks the values of some of the members of a record: type RoadSystem = { RoadName : string Distance : float Location : string } let describe (road : RoadSystem) = printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" road.RoadName if road.Distance > 0.00 then printfn "Distance: %0.2f miles" road.Distance else printfn "Distance: Unknown" match road.Location with | "" -> printfn "Location: Unknown\n" | _ -> printfn "Location: %s\n" road.Location let wa = { RoadName = "Wisconsin Avenue"; Distance = -1.00; Location = "" } describe wa This would produce: Road System Database =----------------------------------------------------= Road Name: Wisconsin Avenue Distance: Unknown Location: Unknown Press any key to continue . . .
A function can be made to return a record. At a minimum, you can have a function that creates its own record object and returns it.Here is an example: let create() = let road = { RoadName = "U.S. Route 1" Distance = 2369.00 Location = "From FortKent, Maine To Key West, Florida" } road // This is the returned record object You can then call the function to retrieve the object it returns and use that object as you see fit. Here is an example: type RoadSystem = { RoadName : string Distance : float Location : string } let create() = let road = { RoadName = "U.S. Route 1" Distance = 2369.00 Location = "From FortKent, Maine To Key West, Florida" } road // This is the returned record object let describe (road : RoadSystem) = printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" road.RoadName printfn "Distance: %0.2f miles" road.Distance printfn "Location: %s\n" road.Location let one = create() describe one On the other hand, a function can be supplied some values as arguments and use all or some of those values to initialize a record and return it. Here is an example: let create name dist loc = let road = { RoadName = name Distance = dist Location = loc } road // This is the returned record object When calling the function, make sure you provide the appropriate values in the order the function expects them. You can get the value produced by that function and use its record object. Here is an example: type RoadSystem = { RoadName : string Distance : float Location : string } let create name dist loc = let road = { RoadName = name Distance = dist Location = loc } road // This is the returned record object let describe (road : RoadSystem) = printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" road.RoadName printfn "Distance: %0.2f miles" road.Distance printfn "Location: %s\n" road.Location let EastWestHighway = create "MD 410" 13.92 "From MD 355 in Bethesda to Landover Hills" describe EastWestHighway This would produce: Road System Database =----------------------------------------------------= Road Name: MD 410 Distance: 13.92 miles Location: From MD 355 in Bethesda to Landover Hills Press any key to continue . . . In such a case, since the function would create and return a record object, you can make it responsible to verify and validate the values of the members in order to produce an appropriate object.
Various combinations of objects of a record can be used in pattern matching to find out what combination is valid for a particular scenario. The pattern to compare should be a sample object. The options can be various objects to which to compare the pattern. You can then take action based on the option that matches the pattern. Here is an example: (* This is a record type representing employees who work in a commercial bank. In this simple example of a record, each employee record determines where the employee is currently working (today) in the office or from home.*) type Employee = { EmployeeNumber : string WorkFrom : string } (* These records indicate where the employee is working today Notice that the same employee number can have more than one record but working either in the office or from home (on different days. *) let e279374o = { EmployeeNumber = "279-374"; WorkFrom = "Office" } let e635753o = { EmployeeNumber = "635-753"; WorkFrom = "Office" } let e279374h = { EmployeeNumber = "279-374"; WorkFrom = "Home" } let e826846o = { EmployeeNumber = "826-846"; WorkFrom = "Office" } let evaluate (empl : Employee) = let mutable employeeCanProcessAccount = false (* This pattern matching is meant to find out where the employee is working today. Employees are not allowed to modify customers' accounts when they work from home. So even if an employee is a manager but working from home, he or she is not allowed to open new bank accounts or to make changes on existing bank accounts*) match empl with | { EmployeeNumber = "279-374"; WorkFrom = "Office" } -> employeeCanProcessAccount <- true | { EmployeeNumber = "635-753"; WorkFrom = "Office" } -> employeeCanProcessAccount <- true | { EmployeeNumber = "279-374"; WorkFrom = "Home" } -> employeeCanProcessAccount <- false | { EmployeeNumber = "826-846"; WorkFrom = "Office" } -> employeeCanProcessAccount <- true | _ -> employeeCanProcessAccount <- true employeeCanProcessAccount let mutable result = evaluate e635753o printfn "Today, employee # e635753o can process customer's accounts: %A" result printfn "______________________________________________________________________" result <- evaluate e279374h printfn "Today, employee # e635753o can process customer's accounts: %A" result This would produce: Today, employee # e635753o can process customer's accounts: true ______________________________________________________________________ Today, employee # e635753o can process customer's accounts: false Press any key to continue . . .
Just like the primitive types, a member of a record can be created as an enumeration type. Of course, you must use an existing enumeration. You can one one of the existing types such as those defined in the .NET Framework, or you can create your own enumeration. Here is an example: type RoadType = | . . . type RoadSystem = { RoadName : string Category : RoadType Distance : float Location : string } When creating an object from the record, make sure you assign a member of the enumeration to the member of the record. You can then access the enumerated member outside the record. Here is an example: type RoadType = | Court | Street | Road | Avenue | Boulevard | StateRoad | StateHighway | Interstate | Unknown type RoadSystem = { RoadName : string Category : RoadType Distance : float Location : string } let USRoute1 = { RoadName = "U.S. Route 1"; Category = RoadType.Road; Distance = 2369.00; Location = "From FortKent, Maine To Key West, Florida"; } printfn "Road System Database" printfn "=----------------------------------------------------=" printfn "Road Name: %s" USRoute1.RoadName printfn "Category: %A" USRoute1.Category printfn "Distance: %0.2f miles" USRoute1.Distance printfn "Location: %s\n" USRoute1.Location This would produce: Road System Database =----------------------------------------------------= Road Name: U.S. Route 1 Category: Road Distance: 2369.00 miles Location: From FortKent, Maine To Key West, Florida Press any key to continue . . . In the same way, you can maipulate the enumerated member in any appropriate way.
A label of a record can be a record type. When creating the label, make sure you appropriately specify its type. Here is an example: type Department = { DepartmentCode : string DepartmentName : string } type Employee = { EmployeeNumber : string FirstName : string LastName : string Department : Department Title : string } Before creating values for the new record, you can first create values for the first record and use its variable as the value in the new object. Here is an example: type Department = { DepartmentCode : string DepartmentName : string } type Employee = { EmployeeNumber : string FirstName : string LastName : string Department : Department Title : string } let dept = { DepartmentCode = "ADMN"; DepartmentName = "Administration, Admissions, and Students Affairs" } let staff = { EmployeeNumber = "161138"; FirstName = "Laura"; LastName = "Fannie"; Department = dept; Title = "Dean of Litterary Studies" } printfn "University Information" printfn "------------------------------------------------------" printfn "Employee Record" printfn "EmployeeN #: %s" staff.EmployeeNumber printfn "First Name: %s" staff.FirstName printfn "LastName: %s" staff.LastName printfn "Department Record ____________________________________" printfn " Department Code: %s" staff.Department.DepartmentCode printfn " Department Name: %s" staff.Department.DepartmentName printfn "Employee Title: %s" staff.Title printfn "======================================================" This would produce: University Information ------------------------------------------------------ Employee Record EmployeeN #: 161138 First Name: Laura LastName: Fannie Department Record ____________________________________ Department Code: ADMN Department Name: Administration, Admissions, and Students Affairs Employee Title: Dean of Litterary Studies ====================================================== Press any key to continue . . . As an alternative, you can specify the values of the member when creating the object. Here is an example: type Department = { DepartmentCode : string DepartmentName : string } type Employee = { EmployeeNumber : string FirstName : string LastName : string Department : Department Title : string } let dept = { DepartmentCode = "ADMN"; DepartmentName = "Administration, Admissions, and Students Affairs" } let staff = { EmployeeNumber = "161138"; FirstName = "Laura"; LastName = "Fannie"; Department = { DepartmentCode = "ADMN"; DepartmentName = "Administration, Admissions, and Students Affairs" }; Title = "Dean of Litterary Studies" }
A member of a class can be created from a record. Just as you can pass a record as argument to a function, you can pass a record to a constructor of a class. In the same way, a property of a class can be created from a record. Here are examples: type Student = { StudentNumber : string; FirstName : string; LastName : string; } type Course = { CourseCode : string; CourseName : string; Credits : int; } type Enrollment(number, date, student, course, semester) = let mutable nbr = number let mutable dte = date let mutable std = student let mutable crs = course let mutable sms = semester member this.EnrollmentNumber with get() = nbr and set(value) = nbr <- value member this.DateEnrolled with get() = dte and set(value) = dte <- value member this.Student with get() = std and set(value) = std <- value member this.Course with get() = crs and set(value) = crs <- value member this.Semester with get() = sms and set(value) = sms <- value let student = { StudentNumber = "502-448"; FirstName = "Jonathan"; LastName = "Davidson" } let course = { CourseCode = "CMSC 108"; CourseName = "Introduction to F# Programming"; Credits = 3 } let enroll = Enrollment(100001, "12/12/2014", student, course, "FALL 2015") printfn "School Registration Summary" printfn "---------------------------" printfn "Enrollment #: %d" enroll.EnrollmentNumber printfn "Enrollment Date: %s" enroll.DateEnrolled printfn "Student Information: %A" enroll.Student printfn "Course Details: %A" enroll.Course printfn "Semester Enrolled: %s" enroll.Semester This would produce: School Registration Summary --------------------------- Enrollment #: 100001 Enrollment Date: 12/12/2014 Student Information: {StudentNumber = "502-448"; FirstName = "Jonathan"; LastName = "Davidson";} Course Details: {CourseCode = "CMSC 108"; CourseName = "Introduction to F# Programming"; Credits = 3;} Semester Enrolled: FALL 2015 Press any key to continue . . . Once you have used a record as a member/property of a class, you can access the individual members of that record and use them as you see fit, such as to display their values. Here are examples: type Student = { StudentNumber : string; FirstName : string; LastName : string; } type Course = { CourseCode : string; CourseName : string; Credits : int; } type Enrollment(number, date, student, course, semester) = let mutable nbr = number let mutable dte = date let mutable std = student let mutable crs = course let mutable sms = semester member this.EnrollmentNumber with get() = nbr and set(value) = nbr <- value member this.DateEnrolled with get() = dte and set(value) = dte <- value member this.Student with get() = std and set(value) = std <- value member this.Course with get() = crs and set(value) = crs <- value member this.Semester with get() = sms and set(value) = sms <- value let student = { StudentNumber = "502-448"; FirstName = "Jonathan"; LastName = "Davidson" } let course = { CourseCode = "CMSC 108"; CourseName = "Introduction to F# Programming"; Credits = 3 } let enroll = Enrollment(100001, "12/12/2014", student, course, "FALL 2015") printfn "School Registration Summary" printfn "------------------------------------------------------" printfn "Enrollment #: %d" enroll.EnrollmentNumber printfn "Enrollment Date: %s" enroll.DateEnrolled printfn "Student Information-----------------------------------" printfn " Student #: %s" enroll.Student.StudentNumber printfn " First Name: %s" enroll.Student.FirstName printfn " LastName: %s" enroll.Student.LastName printfn "Course Details----------------------------------------" printfn " Course Code: %s" enroll.Course.CourseCode printfn " Course Name: %s" enroll.Course.CourseName printfn " Course Credits: %d" enroll.Course.Credits printfn "Semester Enrolled: %s" enroll.Semester printfn "======================================================" This would produce: School Registration Summary ------------------------------------------------------ Enrollment #: 100001 Enrollment Date: 12/12/2014 Student Information----------------------------------- Student #: 502-448 First Name: Jonathan LastName: Davidson Course Details---------------------------------------- Course Code: CMSC 108 Course Name: Introduction to F# Programming Course Credits: 3 Semester Enrolled: FALL 2015 ====================================================== Press any key to continue . . .
We know that a record is structural type that contains named members where each member has a type. Here is an example: type Country = { Continent: string Name : string Capital : string Area : uint32 InternetCode: string } A generic record is one where the data type of one or more members is not specified. To create a generic record, after the name of the record, type <>. Inside the operator, if all record members use the same type, enter a letter or word precedede by '. In the body of the record, use the apostrophe and the generic letter or word in place of the data type. Here is an example: type Country<'T> = { Continent : 'T Name : 'T Capital : 'T } Remember that, to use a record, you can declare a variable and give a value to each member. Here are examples: type Country<'T> = { Continent : 'T Name : 'T Capital : 'T } let Ecuador = { Continent = "South America" Name = "Ecuador" Capital = "Quito" } printfn "%A" Ecuador If the various members of the record use different types, use two letters or words inside the <> operator applied to the name of the record. On the right side of each member of the record, apply the desired generic letter or generic word. Here are examples: type Country<'s, 'i> = { Continent : 's Name : 's Capital : 's Area : 'i InternetCode : 's } let Ecuador = { Continent = "South America" Name = "Ecuador" Capital = "Quito" Area = 283561u InternetCode = "ec" } printfn "%A" Ecuador
When we started using variables, we were introduced to reference cells and we saw how to use them to control the properties of a class. To actually support the concept of getting a reference to th cell memory where a variable is stored, the F# language provides a built-in generic record named Ref define in the Microsoft.FSharp.Core namespace. The Ref record supports various operators and is equipped with a property and a field. We already know that, to declare a variable and get a reference cell where it would be located, we can assign an initial value preceded with the ref keyword. Here is an example: let price = ref 45.00
To change the value of the variable, you can use the := operator. Another technique is to use the following formula: (:=) variable-name value
Here is an example: let price = ref 45.00
// . . .
(:=) price 38.75
To get the value of the variable, you can apply the ! operator before the name of the variable. Another technique is to use the following formula: (!) variable-name
Here is an example: let price = ref 45.00;
printfn "Item Price: $%0.02f" ((!) price)
To support the value of the variable, the Ref record is equipped with a property named Value and a field named contents. Both allow you to get the value of the variable. Here examples of using them let unitPrice = 124.95 let markedPrice = ref 0.00; let discountRate = ref 25.00; markedPrice.Value <- unitPrice printfn "Item Price: $%0.02f" ((!) markedPrice); (:=) markedPrice (unitPrice - (!discountRate * unitPrice / 100.00)) printfn "Discount Price: $%0.02f\n" markedPrice.contents; This would produce: Item Price: $124.95 Discount Price: $93.71 Press any key to continue . . . The Ref.contents field and the Ref.Value property both also allow you to change the value of the variable. This is done by using the <- operator and the value to assign. Here are examples: let unitPrice = 124.95
let markedPrice = ref 0.00;
let discountRate = ref 25.00;
markedPrice.Value <- unitPrice
printfn "Item Price: $%0.02f" ((!) markedPrice);
(:=) markedPrice (unitPrice - (!discountRate * unitPrice / 100.00))
printfn "Discount Rate: %0.02f%s" discountRate.Value "%"
printfn "Price after Discount: $%0.02f" markedPrice.contents;
discountRate.Value <- 50.00
markedPrice.contents <- !markedPrice - (discountRate.Value * !markedPrice / 100.00)
printfn "Discount Rate: %0.02f%s" discountRate.Value "%"
printfn "New Marked Value: $%0.02f\n" markedPrice.contents;
This would produce: Item Price: $124.95 Discount Rate: 25.00% Price after Discount: $93.71 Discount Rate: 50.00% New Marked Value: $46.86 Press any key to continue . . . |
|
|||||||||||||||||||||||||||||||||
|