Introduction to Records
Introduction to Records
Fundamentals of Records
Introduction
A record is a group of variables that are considered as one entity. That is, inside the record, you can create (declare) one or more variables and the variables can be of different types. Then, when you need the services of the record, you can either access the record as a whole or access its members individually.
Creating a Record
The basic formula to create a record is:
type record-name = { labels }
You start with the type keyword, followed by a name. The name of the record follows the rules of names of types. After the name, type = followed by an opening and a closing curly brackets. This would be done as follows:
type Road = { ... }
A Label in a Record
Inside the brackets, create one or more members. A member in a record is also called a label. The labels are separated by semicolons. Each label must use the following formula:
label-name : data-type
That is, each label must be created with a name and its data type, both separated by a colon.
A record can have just one label. Here is an example:
type Student = { FullName : string }
Otherwise, a record can have as many labels as you want. You can create the members on the same line. In that case, separate the members with semicolons. Here is an example:
type Student = { ID : int; FirstName : string; LastName : string; Gender : char }
If there are many labels or to make the code easier to read, you can list the labels on different lines, or each on its own line. Here is an example:
type Student = { ID : int; FirstName : string; LastName : string; Gender : char }
If you use this technique, you can omit the semicolons. Here is an example:
type Student = { ID : int FirstName : string LastName : string Gender : char }
Just like you can create one record in a file, you can created as many records as you want in the same file.
Initializing a Record
Before using a record, you should assign a value to each of its labels. You do this by creating a record expression. To create a record expression, use the following formula:
let variable-name = { label-name1 = value1; label-name2 = value2; . . .; label-name_n = value_n }
As always, start with let followed by a name for the variable and assign curly brackets to it. Inside the brackets, enter each label of the record and assign a value to it; separate them with semicolons. Here is an example:
type Student = {
ID : int
FirstName : string
LastName : string
Gender : char
}
let std = { ID = 773946; FirstName = "Amir"
LastName = "Shalloub" Gender = 'M' }
Remember that you can write each label on its own line to make the code easier to read, in which case you can omit the semicolons:
type Student = {
ID : int
FirstName : string
LastName : string
Gender : char
}
let std = {
ID = 773946
FirstName = "Amir"
LastName = "Shalloub"
Gender = 'M'
}
Notice that the name of the record is not specified in the declaration, but the compiler must be able to identify or recognize the labels that are being accessed in the curly brackets of the variable. This also means that the record must be created before the variable that initializes it.
Introduction to Using a Record
Accessing a Record
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 close this window . . .
Accessing the Labels of a Record
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 close this window . . .
The Type of an Object
When creating an object from a record, the compiler is able to identify the record for which you are creating the object. In some cases, and sometimes this is helpful or necessary, you can or should specify the type of the object. To this, when declaring the variable, after the name of the object, type a colon followed by the name of the record. Here is an example:
type Tractor = { ModelName : string EnginePower : float LiftCapacity : int MowerHeight : int Price : float } let machine : Tractor = { ModelName = "MW9724" EnginePower = 21.5 LiftCapacity = 754 MowerHeight = 60 Price = 13_050 } stdout.WriteLine("Tractor") printfn "%A" machine stdout.WriteLine("================================")
This would produce:
Tractor { ModelName = "MW9724" EnginePower = 21.5 LiftCapacity = 754 MowerHeight = 60 Price = 13050.0 } ================================ Press any key to close this window . . .
Using many Records
In an application, you can create and/or use many records. Here is an example:
type Tractor = {
ModelName : string
EnginePower : float
LiftCapacity : int
MowerHeight : int
Price : float
}
type VehicleRegistration = {
TagNumber : string
Make : string
Model : string
Year : int
}
let vr : VehicleRegistration = {
TagNumber = "HPR-385"
Make = "Ford"
Model = "Escape"
Year = 2020
}
let machine : Tractor = {
ModelName = "MW9724"
EnginePower = 21.5
LiftCapacity = 754
MowerHeight = 60
Price = 13_050
}
stdout.WriteLine("Vehicle Registration")
printfn "%A" vr
stdout.WriteLine("--------------------------------")
stdout.WriteLine("Tractor")
printfn "%A" machine
stdout.WriteLine("================================")
This would produce:
Vehicle Registration { TagNumber = "HPR-385" Make = "Ford" Model = "Escape" Year = 2020 } -------------------------------- Tractor { ModelName = "MW9724" EnginePower = 21.5 LiftCapacity = 754 MowerHeight = 60 Price = 13050.0 } ================================ Press any key to close this window . . .
Sometimes, two or more records may have the labels with the same names. Here are examples:
type Student = { ID : int FirstName : string LastName : string Gender : char } type Employee = { ID : int FirstName : string LastName : string Gender : char }
Notice that both the Student and the Employee records have the exact same labels. This situation qualifies as ambiguous (common in functional and logical languages). In this case, when you declare a variable that initializes a record, the variable will use the record that is closest to it, which is the most recently created record. In our case, this would be the Employee record. Here is an example:
type Student = { ID : int FirstName : string LastName : string Gender : char } type Employee = { ID : int FirstName : string LastName : string Gender : char } let std = { ID = 773946 FirstName = "Amir" LastName = "Shalloub" Gender = 'M' }
If you have different records that have labels that use the same name, when declaring a variable that initializes them, you should qualify one or each label in the curly brackets of the variable. To do this, type the name of the record, followed by a period, and followed by the name of the label. Then assign the appropriate value to the label. 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 Student.FirstName = "Amir" Student.LastName = "Shalloub" Student.Gender = 'M' } let contractor = { Employee.ID = 50225 Employee.FirstName = "Hellie" Employee.LastName = "Pastore" Employee.Gender = 'F' }
In the same way, when accessing a member of an object, you should qualify the member with the name of its 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 Student.FirstName = "Amir" Student.LastName = "Shalloub" Student.Gender = 'M' } let contractor = { Employee.ID = 50225 Employee.FirstName = "Hellie" Employee.LastName = "Pastore" Employee.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 printfn "========================"
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 close this window . . .
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 object(s). 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 close this window . . .
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 close this window . . .
A Mutable Field
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 close this window . . .
Records and Functions
Passing a Record
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 close this window . . .
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 close this window . . .
Returning a Record
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 close this window . . .
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.
Pattern Matching
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 close this window . . .
Records and Other Types
Records and Enumerations
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 use 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 close this window . . .
In the same way, you can manipulate the enumerated member in any appropriate way.
A Record as a Record Label
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 close this window . . .
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" }
Records and Classes
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 close this window . . .
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 close this window . . .
Generic Records
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
Built-In Records: Reference Cells
Introduction
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 defined in the Microsoft.FSharp.Core namespace. The Ref record supports various operators and is equipped with a property and a field.
Creating a Reference Cell
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
Getting the Value of a Reference Cell
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)
The Contents of a Reference Cell
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 close this window . . .
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 close this window . . .
|
|||
Previous | Copyright © 2009-2024, FunctionX | Wednesday 1 November 2023 | Next |
|