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