Fundamentals of Patterns

Introduction

In previous lessons, to deal with conditions, we created if...else expressions, and their variants. Those operations ask the compiler to consider various situations, one after another. Another, sometimes better, option is to ask the compiler to directly locate the specific situation you want to deal with. This approach is referred to as pattern matching.

Practical Learning: Matching a String

1. Start Microsoft Visual Studio (if Microsoft Visual Studio was already opened, on its main menu, click File -> New -> Project...) and create a new Console App that supports .NET 7.0 (Standard Term Support) named TaxPreparation05
2. Change the document as follows:
```printfn "=========================================="
printfn " - Amazing DeltaX - State Income Tax -"
printfn "=========================================="

let mutable stateName       = ""
let mutable taxRate = 0.00

printfn "Enter the information for tax preparation"
printfn "States"
printfn " AR - Arkansas"
printfn " FL - Florida"
printfn " GA - Georgia"
printfn " IL - Illinois"
printfn " IN - Indiana"
printfn " KY - Kentucky"
printfn " MA - Massachusetts"
printfn " MI - Michigan"
printfn " MO - Missouri"
printfn " MS - Mississippi"
printfn " NH - New Hampshire"
printfn " NC - North Carolina"
printfn " PA - Pennsylvania"
printfn " SD - South Dakota"
printfn " TN - Tennessee"
printfn " TX - Texas"
printfn " UT - Utah"
printfn " WA - Washington"
printfn " WY - Wyoming"
printf "Enter State Abbreviation: "
let abbr : string = stdin.ReadLine()
printfn "--------------------------------------------"

printf "Gross Salary:             "

let taxAmount = grossSalary * taxRate / 100.00
let netPay    = grossSalary - taxAmount

printfn "============================================"
printfn " - Amazing DeltaX - State Income Tax -"
printfn "--------------------------------------------"
printfn \$"Gross Salary: {grossSalary:f}"
printfn \$"State:        {stateName}"
printfn "Tax Rate:     %0.2f%c" taxRate '%'
printfn "--------------------------------------------"
printfn \$"Tax Amount:   {taxAmount:f}"
printfn \$"Net Pay:      {netPay:f}"
printfn "============================================"```
4. For the State Abbreviation, type FL and press Enter
5. For the Gross Salary, type 1558.85 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: FL
--------------------------------------------
Gross Salary: 1558.85
============================================
- Amazing DeltaX - State Income Tax -
--------------------------------------------
Gross Salary: 1558.85
State:
Tax Rate:     0.00%
--------------------------------------------
Tax Amount:   0.00
Net Pay:      1558.85
============================================
Press any key to close this window . . .```
8. For the State Abbreviation, type KY and press Enter
9. For the Gross Salary, type 1558.85 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: KY
--------------------------------------------
Gross Salary:             1558.85
============================================
- Amazing DeltaX - State Income Tax -
--------------------------------------------
Gross Salary: 1558.85
State:
Tax Rate:     0.00%
--------------------------------------------
Tax Amount:   0.00
Net Pay:      1558.85
============================================
Press any key to close this window . . .```

Matching an Expression

If you have an expression that can produce many outcomes but only one of them must be considered, you can validate it using the match keyword. The formula to follow is:

```match expression with
| condition-1 -> result-1
| condition-2 -> result-2
| . . .
| condition-x -> result-x```

The match and the with keywords are required. The expression can be the name of a variable whose value will be tested. The results of testing the expression will each be validated in the next lines. Each line starts with | (a pipe) and a value from the expression. This produces a result from the condition X, which is followed by the -> operator. Each condition has a body. The body is introduced by the -> operator. On the right side of that -> operator, define what you want process for that particular condition.

Matching an Integer

One of the types of values you can try to match is an integer. In most cases, a match statement behaves like an if conditional statement. Consider the following code that uses an if conditional statement:

```let number = 248
let mutable conclusion = "That number is not right."

if number = 248 then
conclusion <- "That number is correct."

printfn "%s" conclusion
printfn "========================================"```

This would produce:

```That number is correct.
========================================
Press any key to close this window . . .```

The same code can be written with a match statement as follows:

```let number = 248;
let conclusion = "That number is not right."

match number with
| 248 ->
conclusion = "That number is correct."

printfn "%s" conclusion
printfn "========================================"```

We know that an if conditional statement can use one or more else options. Here is an example:

```let mutable incomeTax = 0.00

printfn "Payroll Evaluation"
printfn "============================================"
printfn "Enter the information to evaluate taxes"
printfn "Frequency by which the payroll is processed:"
printfn "1 - Weekly"
printfn "2 - Biweekly"
printfn "3 - Semimonthly"
printfn "4 - Monthly"
printf "Enter Payroll Frequency: "
printfn "--------------------------------------------"

printf "Gross Salary:            "

if frequency = 1 then
incomeTax <- 271.08 + (grossSalary * 24.00 / 100.00)
elif frequency = 2 then
incomeTax <- 541.82 + (grossSalary * 24.00 / 100.00)
elif frequency = 3 then
incomeTax <- 587.12 + (grossSalary * 24.00 / 100.00)
elif frequency = 4 then
incomeTax <- 1174.12 + (grossSalary * 24.00 / 100.00)

printfn "============================================"
printfn "Payroll Evaluation"
printfn "--------------------------------------------"
printfn "Gross Salary: %18.02f" grossSalary
printfn "Income Tax:   %18.02f" incomeTax
printfn "============================================"```

Here is an example of running the program:

```Payroll Evaluation
============================================
Enter the information to evaluate taxes
Frequency by which the payroll is processed:
1 - Weekly
2 - Biweekly
3 - Semimonthly
4 - Monthly
Enter Payroll Frequency: 3
--------------------------------------------
Gross Salary:            1552.86
============================================
Payroll Evaluation
--------------------------------------------
Gross Salary:            1552.86
Income Tax:               959.81
============================================

Press any key to close this window . . .```

In the same way, each section of a matching pattern can use a natural number. Here is an example:

```let mutable incomeTax = 0.00

printfn "Payroll Evaluation"
printfn "============================================"
printfn "Enter the information to evaluate taxes"
printfn "Frequency by which the payroll is processed:"
printfn "1 - Weekly"
printfn "2 - Biweekly"
printfn "3 - Semimonthly"
printfn "4 - Monthly"
printf "Enter Payroll Frequency: "
printfn "--------------------------------------------"

printf "Gross Salary:            "

match frequency with
| 1 ->
incomeTax <- 271.08 + (grossSalary * 24.00 / 100.00)
| 2 ->
incomeTax <- 541.82 + (grossSalary * 24.00 / 100.00)
| 3 ->
incomeTax <- 587.12 + (grossSalary * 24.00 / 100.00)
| 4 ->
incomeTax <- 1174.12 + (grossSalary * 24.00 / 100.00)

printfn "============================================"
printfn "Payroll Evaluation"
printfn "--------------------------------------------"
printfn "Gross Salary: %18.02f" grossSalary
printfn "Income Tax:   %18.02f" incomeTax
printfn "============================================"```

Matching a String

Besides a natural number, a matching pattern can compare its expression to strings. In this case, each section uses a string or an expression that evaluates to a string.

Practical Learning: Matching by Some Strings

1. Change the document as follows:
```printfn "=========================================="
printfn " - Amazing DeltaX - State Income Tax -"
printfn "=========================================="

let mutable stateName : string = ""
let mutable taxRate   = 0.00

printfn "Enter the information for tax preparation"
printfn "States"
printfn " AR - Arkansas"
printfn " FL - Florida"
printfn " GA - Georgia"
printfn " IL - Illinois"
printfn " IN - Indiana"
printfn " KY - Kentucky"
printfn " MA - Massachusetts"
printfn " MI - Michigan"
printfn " MO - Missouri"
printfn " MS - Mississippi"
printfn " NH - New Hampshire"
printfn " NC - North Carolina"
printfn " PA - Pennsylvania"
printfn " SD - South Dakota"
printfn " TN - Tennessee"
printfn " TX - Texas"
printfn " UT - Utah"
printfn " WA - Washington"
printfn " WY - Wyoming"
printf "Enter State Abbreviation: "
let abbr : string = stdin.ReadLine()
printfn "--------------------------------------------"

printf "Gross Salary:             "

match abbr with
| "CO" ->
taxRate   <- 4.63

| "FL" ->
taxRate   <- 0.00
stateName <- "Florida"

| "IL" ->
taxRate   <- 4.95
stateName <- "Illinois"

| "IN" ->
taxRate   <- 3.23
stateName <- "Indiana"

| "KY" ->
taxRate   <- 5.00
stateName <- "Kentucky"

| "MA" ->
taxRate   <- 5.00
stateName <- "Massachusetts"

| "MI" ->
taxRate   <- 4.25
stateName <- "Michigan"

| "NC" ->
taxRate   <- 5.25
stateName <- "North Carolina"

| "NH" ->
taxRate   <- 5.00
stateName <- "New Hampshire"

| "NV" ->
taxRate   <- 0.00

| "PA" ->
taxRate   <- 3.07
stateName <- "Pennsylvania"

| "TN" ->
taxRate   <- 1.00
stateName <- "Tennessee"

| "TX" ->
taxRate   <- 0.00
stateName <- "Texas"

| "UT" ->
taxRate   <- 4.95
stateName <- "Utah"

| "WA" ->
taxRate   <- 0.00
stateName <- "Washington"

| "WY" ->
taxRate   <- 0.00
stateName <- "Wyoming"

let taxAmount = grossSalary * taxRate / 100.00
let netPay    = grossSalary - taxAmount;

printfn "============================================"
printfn " - Amazing DeltaX - State Income Tax -"
printfn "--------------------------------------------"
printfn \$"Gross Salary: {grossSalary:f}"
printfn \$"State:        {stateName}"
printfn "Tax Rate:     %0.2f%c" taxRate '%'
printfn "--------------------------------------------"
printfn \$"Tax Amount:   {taxAmount:f}"
printfn \$"Net Pay:      {netPay:f}"```
3. For the State Abbreviation, type CO and press Enter
4. For the Gross Salary, type 1558.85 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: CO
--------------------------------------------
Gross Salary:             1558.85
============================================
- Amazing DeltaX - State Income Tax -
--------------------------------------------
Gross Salary: 1558.85
Tax Rate:     4.63%
--------------------------------------------
Tax Amount:   72.17
Net Pay:      1486.68
============================================
Press any key to close this window . . .```
7. For the State Abbreviation, type KY and press Enter
8. For the Gross Salary, type 1558.85 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: KY
--------------------------------------------
Gross Salary:             1558.85
============================================
- Amazing DeltaX - State Income Tax -
--------------------------------------------
Gross Salary: 1558.85
State:        Kentucky
Tax Rate:     5.00%
--------------------------------------------
Tax Amount:   77.94
Net Pay:      1480.91
============================================
Press any key to close this window . . .```
10. Create a new Console App that supports the .NET 6.0 (Long-Term Support) and named SimpleInterest1

Matching an Enumeration

A matching pattern can use an enumeration. In this case, each section can use a member of an enumeration.

Practical Learning: Matching an Enumeration

1. Change the Program.cs document as follows:
```type CompoundFrequency =
| Daily
| Weekly
| Monthly
| Quaterly
| Semiannually
| Annually

let mutable frequency = 0.00
let mutable interestRate = 0.00
let periods = 42
let mutable compounding = CompoundFrequency.Monthly

printfn "Simple Interest"
printfn "--------------------------------------------------------"
printfn "Provide the values that will be used to evaluate a loan."
printf "Principal: "
printfn "--------------------------------------------------------"
printfn "Compound Frequencies"
printfn "1. Weekly"
printfn "2. Monthly"
printfn "3. Quaterly"
printfn "4. Semiannually"
printfn "5. Annually"

if choice = "1" then
compounding <- CompoundFrequency.Weekly
elif choice = "2" then
compounding <- CompoundFrequency.Monthly
elif choice = "3" then
compounding <- CompoundFrequency.Quaterly
elif choice = "4" then
compounding <- CompoundFrequency.Semiannually
elif choice = "5" then
compounding <- CompoundFrequency.Annually
else
compounding <- CompoundFrequency.Daily

match compounding with
| CompoundFrequency.Daily ->
interestRate <- 8.95
frequency    <- 365.00

| CompoundFrequency.Weekly ->
interestRate <- 52.00
frequency    <- 11.95

| CompoundFrequency.Monthly ->
interestRate <- 12.00
frequency    <- 14.75

| CompoundFrequency.Quaterly ->
interestRate <- 4.00
frequency    <- 18.85

| CompoundFrequency.Semiannually ->
interestRate <- 2.00
frequency    <- 22.55

| CompoundFrequency.Annually ->
interestRate <- 1.00
frequency    <- 26.25

let iRate = interestRate / float 100
let per = float periods / frequency
let interestAmount = principal * iRate * per

printfn "========================================================="
printfn "Simple Interest"
printfn "--------------------------------------------------------"
printfn "Principal:          %0.02f" principal
printfn "Interest Rate:      %0.02f %c" interestRate '%'
printfn "Periods:            %i months" periods
printfn "-------------------------------"
printfn "Interest Amount:    %0.02f" interestAmount
printfn "Future Value:       %0.02f" (principal + interestAmount)
printfn "========================================================="```
2. To execute, press Ctrl + F5
3. When requested, type the Principal as 7248.95 and press Enter
4. For the compound frequency, type 2 and press Enter:
```Simple Interest
--------------------------------------------------------
Provide the values that will be used to evaluate a loan.
Principal: 7248.95
--------------------------------------------------------
Compound Frequencies
1. Weekly
2. Monthly
3. Quaterly
4. Semiannually
5. Annually
=========================================================
Simple Interest
--------------------------------------------------------
Principal:          7248.95
Interest Rate:      14.75%
Periods:            42 months
-------------------------------
Interest Amount:    3742.27
Future Value:       10991.22
=========================================================
Press any key to close this window . . .```
6. To open a recent project, on the main menu, click File -> Recent Projects and Solutions, and click TaxPreparation05

Conditionally Matching

Matching a Boolean Variable

Besides natural numbers and strings, a matching pattern can process logical expressions. To make it happen, you can first declare a Boolean variable. You can also use an expression that holds a Boolean value. Pass the Boolean value or expression to match. For each section of the matching pattern, use one of the possible Boolean outcomes. At a minimum, if you are using a Boolean variable, one section can use true and the other can process the false outcome. Here is an example:

```let mutable conclusion = ""
let emplTitle          = "Manager"
let emplIsManager      = emplTitle = "Manager"

match emplIsManager with
| true ->
conclusion <- "The employee is a manager."

| false ->
conclusion <- "The staff member is a regular employee."

printfn "%s" conclusion
printfn "========================================"```

This would produce:

```The employee is a manager.
========================================
Press any key to close this window . . .```

Matching a Boolean Expression

In the previous example, we included a Boolean variable to match. Otherwise, if you have a Boolean expression, you can pass it directly to match. Here is an example:

```let mutable conclusion = ""
let emplTitle          = "Manager"

match emplTitle = "Manager" with
| true ->
conclusion <- "The employee is a manager."

| false ->
conclusion <- "The staff member is a regular employee."

printfn "%s" conclusion
printfn "========================================"```

In the same way, since every conditional operation produces a Boolean value, it can be used for a matching pattern. Here is an example:

```let timeWorked = 30.00

// If TimeWorked >= 40
match timeWorked >= 40.00 with
| true ->
printfn "The employee works full-time."

| false ->
printfn "The staff member worked part-time."

printfn "========================================"```

As a result, you will see that in many cases, an if conditional statement such such as this:

```printfn "FUN DEPARTMENT STORE"
printfn "======================================================="
printfn "Payroll Preparation"
printfn "-------------------------------------------------------"
printfn "Enter the following pieces of information"
printfn "-------------------------------------------------------"
printfn "Employee Information"
printfn "-------------------------------------------------------"
printf "First Name:    "
let firstName : string = stdin.ReadLine()
printf "Last Name:     "
let lastName : string = stdin.ReadLine()
printf "Hourly Salary: "
printfn "-------------------------------------------------------"
printfn "Time worked"
printfn "-------------------------------------------------------"

printf "Monday:        "

printf "Tuesday:       "

printf "Wednesday:     "

printf "Thursday:      "

printf "Friday:        "

let timeWorked = mon + tue + wed + thu + fri

let mutable regTime  = 0.00
let mutable overtime = 0.00
let mutable regPay   = 0.00
let mutable overPay  = 0.00

if timeWorked <= 40.00 then
regTime   <- timeWorked
regPay    <- hSalary * timeWorked
overtime  <- 0.00
overPay   <- 0.00
else
regTime   <- 40.00
regPay    <- hSalary * 40.00
overtime  <- timeWorked - 40.00
overPay   <- hSalary * 1.50 * overtime

let netPay = regPay + overPay

printfn "+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+"
printfn "FUN DEPARTMENT STORE"
printfn "======================================================="
printfn "Payroll Evaluation"
printfn "======================================================="
printfn "Employee Information"
printfn "-------------------------------------------------------"
printfn \$"Full Name:     {firstName} {lastName}"
printfn \$"Hourly Salary: {hSalary:f}"
printfn "======================================================="
printfn "Time Worked Summary"
printfn "--------+---------+-----------+----------+-------------"
printfn " Monday | Tuesday | Wednesday | Thursday | Friday"
printfn "--------+---------+-----------+----------+-------------"
printfn \$"  {mon:f}  |   {tue:f}  |    {wed:f}   |  {thu:f}   |  {fri:f}"
printfn "========+=========+===========+==========+============="
printfn "                                   Pay Summary"
printfn "-------------------------------------------------------"
printfn "                                   Time     Pay"
printfn "-------------------------------------------------------"
printfn "                     Regular: %10.2f%10.2f" regTime regPay
printfn "-------------------------------------------------------"
printfn "                     overtime:%10.2f%10.2f" overtime overPay
printfn "======================================================="
printfn "                     Net Pay: %20.2f" netPay
printfn "======================================================="```

can also be implemented as a matching pattern like this:

```printfn "FUN DEPARTMENT STORE"
printfn "======================================================="
printfn "Payroll Preparation"
printfn "-------------------------------------------------------"

. . .

match timeWorked <= 40.00 with
| true ->
regTime   <- timeWorked
regPay    <- hSalary * timeWorked
overtime  <- 0.00
overPay   <- 0.00
| false ->
regTime   <- 40.00
regPay    <- hSalary * 40.00
overtime  <- timeWorked - 40.00
overPay   <- hSalary * 1.50 * overtime

let netPay = regPay + overPay

. . .```

Here is an example of running the program:

```FUN DEPARTMENT STORE
=======================================================
Payroll Preparation
-------------------------------------------------------
Enter the following pieces of information
-------------------------------------------------------
Employee Information
-------------------------------------------------------
First Name:    Jacob
Last Name:     Melman
Hourly Salary: 22.84
-------------------------------------------------------
Time worked
-------------------------------------------------------
Monday:        8
Tuesday:       7.50
Wednesday:     9.50
Thursday:      10.50
Friday:        8
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
FUN DEPARTMENT STORE
=======================================================
Payroll Evaluation
=======================================================
Employee Information
-------------------------------------------------------
Full Name:     Jacob Melman
Hourly Salary: 22.84
=======================================================
Time Worked Summary
--------+---------+-----------+----------+-------------
Monday | Tuesday | Wednesday | Thursday | Friday
--------+---------+-----------+----------+-------------
8.00  |   7.50  |    9.50   |  10.50   |  8.00
========+=========+===========+==========+=============
Pay Summary
-------------------------------------------------------
Time     Pay
-------------------------------------------------------
Regular:      40.00    913.60
-------------------------------------------------------
overtime:      3.50    119.91
=======================================================
Net Pay:              1033.51
=======================================================

Press any key to close this window . . .```

Practical Learning: Matching Unknown Outcomes

2. For the State Abbreviation, type USA and press Enter
3. For the Gross Salary, type 1000 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: USA
--------------------------------------------
Gross Salary:             1000
Unhandled exception. Microsoft.FSharp.Core.MatchFailureException: The match cases were incomplete
at . . .\Program.fs:line 102

Press any key to close this window . . .```
4. Notice that the program produces an error.

Default Selection

Introduction

When you create a match statement, you provide the values that must each be processed. Unfortunately, in most cases, at least one value is left out. As a result, you must tell the compiler what to do for (the) value(s) that cannot be processed. To assist you with this, the F# language provides an operator as the underscore _. In some cases, you can have a situation where you want to deal with only the default case. In that case, the formula to follow is:

`match expression with | _ ->statement(s)`

In most cases, you will deaul with known values and at lease one unknown value. For that scenario, the formula to follow is:

```match expression with
| condition-1 -> result-1
| condition-2 -> result-2
| . . .
| condition-x -> result-x
| _ ->statement(s)```

Processing a Default Value

Consider a program with the following code:

```let number = 1
let mutable conclusion = "That number is not right."

if number = 1 then conclusion <- "That number is correct."

printfn "%s" conclusion
printfn "===================================="```

This would produce:

```That number is correct.
====================================

Press any key to close this window . . .```

As mentioned earlier, you can create a matching pattern that has only a default section. That situation is the same as having a simple if condition. As a result, the above code can be converted into a matching pattern with a default section as follows:

```let number = 1
let mutable conclusion = "That number is not right."

match number with | _ -> conclusion <- "That number is correct."

printfn "%s" conclusion
printfn "========================================"```

Processing Unknown Values

Consider the following program:

```let mutable startingSalary = 16_000
let mutable employmentStatus = ""

printfn "Employment Status:"
printfn "f - Full-Time"
printfn "p - Part-Time"
printfn "c - Contractor"
printfn "--------------------------"
printf "Enter Employment Status: ";

match status with
| 'f' ->
startingSalary <- 40_000
employmentStatus <- "Full-Time"
| 'p' ->
employmentStatus <- "Part-Time"
startingSalary <- 32_000
| 'c' ->
startingSalary <- 24_000
employmentStatus <- "Contractor"

printfn "Employee Record"
printfn "----------------------------------"
printfn "Employment Status:      %s" employmentStatus
printfn "Starting Yearly Salary: %i" startingSalary
printfn "=================================="```

Notice that this code produces a warning. Here is an example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
--------------------------
Enter Employment Status: p
Employee Record
----------------------------------
Employment Status:      Part-Time
Starting Yearly Salary: 32000
==================================

Press any key to close this window . . .```

Here is another example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
--------------------------
Enter Employment Status: c
Employee Record
----------------------------------
Employment Status:      Contractor
Starting Yearly Salary: 24000
==================================

Press any key to close this window . . .```

Here is another example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
--------------------------
Enter Employment Status: f
Employee Record
----------------------------------
Employment Status:      Full-Time
Starting Yearly Salary: 40000
==================================

Press any key to close this window . . .```

Here is one more example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
--------------------------
Enter Employment Status: u
Unhandled exception. Microsoft.FSharp.Core.MatchFailureException: The match cases were incomplete
at . . .\Program.fs:line 21

Press any key to close this window . . .```

Notice that, this time, when we provide a value that is not expected, the program produces an error. As seen so far, in most cases, your matching statements will deal with different values. When there is at least one value that you did not consider, you should include the underscore section. Here is an example:

```let mutable startingSalary = 16_000
let mutable employmentStatus = ""

printfn "Employment Status:"
printfn "f - Full-Time"
printfn "p - Part-Time"
printfn "c - Contractor"
printfn "----------------------------------"
printf "Enter Employment Status: ";

match status with
| 'f' ->
startingSalary <- 40_000
employmentStatus <- "Full-Time"
| 'p' ->
employmentStatus <- "Part-Time"
startingSalary <- 32_000
| 'c' ->
startingSalary <- 24_000
employmentStatus <- "Contractor"
| _ ->
startingSalary <- 22_000
employmentStatus <- "Unknown"

printfn "Employee Record"
printfn "----------------------------------"
printfn "Employment Status:      %s" employmentStatus
printfn "Starting Yearly Salary: %i" startingSalary
printfn "=================================="```

Here is an example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
----------------------------------
Enter Employment Status: a
Employee Record
----------------------------------
Employment Status:      Unknown
Starting Yearly Salary: 22000
==================================

Press any key to close this window . . .```

If you create an underscore section in your matching pattern, that underscore section should always be the last (unlike C# where the default section can appear anywhere, such as in the beginning of the cases or between any two cases).

Ignoring the Default Outcome

Although you should always anticipate the default case, sometimes, you can ignore it or deal with it in other section of your program. Still, in mose cases, if you don't create an underscore case, you program will present a warning, which could result in an error if the user provides a value that doesn't one of those the program is prepared for. To let you create a default case that doesn't present functionality for it, the F# language provides the empty parentheses operator. To use it, for the body of the last case, simply type () and don't provide any other code for it. Here is an example:

```let mutable startingSalary = 16_000
let mutable employmentStatus = "Unknown"

printfn "Employment Status:"
printfn "f - Full-Time"
printfn "p - Part-Time"
printfn "c - Contractor"
printfn "----------------------------------"
printf "Enter Employment Status: ";

match status with
| 'f' ->
startingSalary <- 40_000
employmentStatus <- "Full-Time"
| 'p' ->
employmentStatus <- "Part-Time"
startingSalary <- 32_000
| 'c' ->
startingSalary <- 24_000
employmentStatus <- "Contractor"
| _ -> ()

printfn "Employee Record"
printfn "----------------------------------"
printfn "Employment Status:      %s" employmentStatus
printfn "Starting Yearly Salary: %i" startingSalary
printfn "=================================="```

Here is an example of running the program:

```Employment Status:
f - Full-Time
p - Part-Time
c - Contractor
----------------------------------
Enter Employment Status: q
Employee Record
----------------------------------
Employment Status:      Unknown
Starting Yearly Salary: 16000
==================================

Press any key to close this window . . .```

Practical Learning: Addressing the Default Outcome

1. Change the document as follows:
```printfn "=========================================="
printfn " - Amazing DeltaX - State Income Tax -"
printfn "=========================================="

let mutable stateName       = ""
let mutable taxRate = 0.00

printfn "Enter the information for tax preparation"
printfn "States"
printfn " AR - Arkansas"
printfn " FL - Florida"
printfn " GA - Georgia"
printfn " IL - Illinois"
printfn " IN - Indiana"
printfn " KY - Kentucky"
printfn " MA - Massachusetts"
printfn " MI - Michigan"
printfn " MO - Missouri"
printfn " MS - Mississippi"
printfn " NH - New Hampshire"
printfn " NC - North Carolina"
printfn " PA - Pennsylvania"
printfn " SD - South Dakota"
printfn " TN - Tennessee"
printfn " TX - Texas"
printfn " UT - Utah"
printfn " WA - Washington"
printfn " WY - Wyoming"
printf "Enter State Abbreviation: "
let abbr : string = stdin.ReadLine()
printfn "--------------------------------------------"

printf "Gross Salary:             "

match abbr with
| "CO" ->
taxRate   <- 4.63

| "FL" ->
taxRate   <- 0.00
stateName <- "Florida"

| "IL" ->
taxRate   <- 4.95
stateName <- "Illinois"

| "IN" ->
taxRate   <- 3.23
stateName <- "Indiana"

| "KY" ->
taxRate   <- 5.00
stateName <- "Kentucky"

| "MA" ->
taxRate   <- 5.00
stateName <- "Massachusetts"

| "MI" ->
taxRate   <- 4.25
stateName <- "Michigan"

| "NC" ->
taxRate   <- 5.25
stateName <- "North Carolina"

| "NH" ->
taxRate   <- 5.00
stateName <- "New Hampshire"

| "NV" ->
taxRate   <- 0.00

| "PA" ->
taxRate   <- 3.07
stateName <- "Pennsylvania"

| "TN" ->
taxRate   <- 1.00
stateName <- "Tennessee"

| "TX" ->
taxRate   <- 0.00
stateName <- "Texas"

| "UT" ->
taxRate   <- 4.95
stateName <- "Utah"

| "WA" ->
taxRate   <- 0.00
stateName <- "Washington"

| "WY" ->
taxRate   <- 0.00
stateName <- "Wyoming"

| _ -> ()

let taxAmount = grossSalary * taxRate / 100.00
let netPay    = grossSalary - taxAmount

printfn "============================================"
printfn " - Amazing DeltaX - State Income Tax -"
printfn "--------------------------------------------"
printfn \$"Gross Salary: {grossSalary:f}"
printfn \$"State:        {stateName}"
printfn "Tax Rate:     %0.2f%c" taxRate '%'
printfn "--------------------------------------------"
printfn \$"Tax Amount:   {taxAmount:f}"
printfn \$"Net Pay:      {netPay:f}"
printfn "============================================"```
3. For the State Abbreviation, type USA and press Enter
4. For the Gross Salary, type 100.00 and press Enter:
```==========================================
- Amazing DeltaX - State Income Tax -
==========================================
Enter the information for tax preparation
States
AR - Arkansas
FL - Florida
GA - Georgia
IL - Illinois
IN - Indiana
KY - Kentucky
MA - Massachusetts
MI - Michigan
MO - Missouri
MS - Mississippi
NH - New Hampshire
NC - North Carolina
PA - Pennsylvania
SD - South Dakota
TN - Tennessee
TX - Texas
UT - Utah
WA - Washington
WY - Wyoming
Enter State Abbreviation: USA
--------------------------------------------
Gross Salary:             100.00
============================================
- Amazing DeltaX - State Income Tax -
--------------------------------------------
Gross Salary: 100.00
State:
Tax Rate:     0.00%
--------------------------------------------
Tax Amount:   0.00
Net Pay:      100.00
============================================

Press any key to close this window . . .```

Nesting Pattern Matching

You can create a pattern matching operation inside another. This is referred to as nesting. Here is an example:

```// -- Annual Compound Interest - Money Borrowed
let principal = 2500
let amountCategory =
if principal < 1000 then 1
elif principal < 2000 then 2
elif principal < 5000 then 3
else 4

let mutable periods = 0
let mutable typeOfPeriods = 3 //"Daily" // "Monthly" "Quarterly" "Annually"
let mutable compounded = "Quarterly"
let numberOfYears = 6
let mutable interestRate = 0.00

match typeOfPeriods with
| 1 ->
compounded <- "Daily"
periods <- 360
match amountCategory with
| 1 -> interestRate <- 2.25 / 100.00
| 2 -> interestRate <- 3.45 / 100.00
| 3 -> interestRate <- 4.35 / 100.00
| _ -> interestRate <- 6.05 / 100.00
| 2 ->
compounded <- "Monthly"
periods <- 12
match amountCategory with
| 1 -> interestRate <- 2.35 / 100.00
| 2 -> interestRate <- 2.95 / 100.00
| 3 -> interestRate <- 4.05 / 100.00
| _ -> interestRate <- 6.85 / 100.00
| 3 ->
compounded <- "Quarterly"
periods <- 4
match amountCategory with
| 1 -> interestRate <- 2.25 / 100.00
| 2 -> interestRate <- 4.30 / 100.00
| 3 -> interestRate <- 5.55 / 100.00
| _ -> interestRate <- 7.35 / 100.00
| 4 ->
compounded <- "Annually"
periods <- 1
match amountCategory with
| 1 -> interestRate <- 3.15 / 100.00
| 2 -> interestRate <- 4.35 / 100.00
| 3 -> interestRate <- 6.25 / 100.00
| _ -> interestRate <- 8.05 / 100.00
| _ -> periods <- 0
interestRate <- 0.00

// Calculation
let compoundInYears = float periods * float numberOfYears
let n1 = float 1 + (interestRate / float periods)
let futureValue = float principal * (n1 ** compoundInYears)

printfn "Deposit Summary"
printfn "--------------------------"
printfn "Amount Deposited: %d" principal
printfn "Interest Rate:    %0.02f%c" (interestRate * 100.00) '%'
printfn "Periods:          %i years" periods
printfn "Compounded:       %s" compounded
printfn "--------------------------"
printfn "Future Value:    %0.02f" futureValue
printfn "=========================="```

This would produce:

```Deposit Summary
--------------------------
Amount Deposited: 2500
Interest Rate:    5.55%
Periods:          4 years
Compounded:       Quarterly
--------------------------
Future Value:    3479.89
==========================
Press any key to close this window . . .```

Practical Learning: Ending the Lesson