Hi! I’m a shouty man.1 Do you miss the switch
statement from languages such
as C, Java, and JavaScript? Or the match
statement from Python? Tired of
writing (or reading) nested conditional expressions like the following?
:include: file=”assets/src/decide/nested.hs”, line=25:40
Say no more. What if I tell you that you can get rid of nested conditional expressions? How would you like to organize your nested conditional expressions according to the cases or conditions you want to match? Curious? Read on.
A conditional expression can be replaced with a guarded equation. To understand
what a guarded equation can do for you, recall the function maxInt
from the
section Multiple parameters:
:include: file=”assets/src/decide/max.hs”, line=27:32
Here is the same function, but written as a guarded equation:
:include: file=”assets/src/decide/max.hs”, line=34:38
And here is the guarded equation translated to a mathematical expression:
\[\text{max}(x,\, y) = \begin{cases} x,& \text{if } x > y,\\[8pt] y,& \text{otherwise}. \end{cases}\]A guarded equation is a function that follows the format
1
2
3
4
5
funcName a b ...
| conditional_1 = result_1
| conditional_2 = result_2
...
| otherwise = result_n
First, we have the name funcName
of the guarded equation. We use the name of
the guarded equation and pass parameters to it in the same way that we apply a
function. A guarded equation is a function. The pipe symbol |
is read as “such
that” and signifies the beginning of a guard. A guard is a conditional, an
expression that evaluates to a boolean value. To the right of the guard is the
equal sign =
, followed by the result corresponding to the guard. The line
1
| conditional_1 = result_1
can be read as, “The value of the function is such that if conditional_1
holds
True
, then the output is result_1
.” The other lines have similar
interpretation. The final line of a guarded equation is
1
| otherwise = result_n
Like the switch
statement (and the label default
) in some languages, Haskell
does not require the guard otherwise
in the final line of your
guarded equation. However, do bear in mind that the guard otherwise
is defined
as otherwise = True
and serves as a catch-all for every case not handled by
the previous guards. Use the guard otherwise
to handle the default output of
your guarded equation.
The body mass index (BMI) is a quick and easy way to assess a person’s health in terms of their weight and height. The formula is given as
\[\text{BMI} = \frac{ \text{weight} }{ \text{height} \times \text{height} }\]where the weight (or mass) is measured in kilograms and the height is measured in metres. According to the US Centers for Disease Control and Prevention (CDC), an adult of 20 years or older can be categorized as follows according to their BMI.
BMI | Status |
---|---|
below 18.5 | underweight |
18.5–24.9 | healthy weight |
25.0–29.9 | overweight |
30.0 or above | obese |
The information in the above table is translated to a guarded equation as follows.
:include: file=”assets/src/decide/bmi.hs”, line=32:39
Different coffee beverages are best served with cups of various sizes. According to this website, the cup sizes corresponding to some drinks are as given below.
Drink | Cup size |
---|---|
espresso | 56–85 ml |
cappuccino | 142–170 ml |
latte | 227–426 ml |
frappuccino | 312–426 ml |
Your mission, should you choose to accept it, is to write a function that takes the name of a caffeinated drink and outputs the corresponding cup size. Did you decline? No problem. Below is a translation of the above table to Haskell code.
:include: file=”assets/src/decide/coffee.hs”, line=27:34
:exercise: Write a guarded equation to determine the minimum of two integers.
:exercise: Rewrite the program :script: file=”assets/src/decide/nested.hs” by using guarded equation.
:exercise: The sign or signum function is defined as follows:
\[\text{sgn}(x) = \begin{cases} -1,& \text{if } x < 0,\\[8pt] 0,& \text{if } x = 0,\\[8pt] 1,& \text{if } x > 0. \end{cases}\]Implement the sign function as a Haskell guarded equation.
:exercise: Repeat the daily saying exercise, but use guarded equation.
:exercise: The triangular function is defined as:
\[\text{tri}(x) = \begin{cases} 1 - |x|,& \text{if } |x| < 1,\\[8pt] 0,& \text{otherwise}. \end{cases}\]Repeat the exercise on absolute value, but implement a guarded equation. Then implement the triangular function as a guarded equation.
:exercise: The size of a college in the USA can be categorized according to the number of students the college has. Refer to the table below.
Students | Size |
---|---|
less than 5,000 | small |
5,000 to 15,000 | medium |
greater than 15,000 | large |
Implement the above table as a guarded equation.
:exercise: In the USA, the size of woman’s clothing can be designated by a number between 0 and 22. We can assign the size to a category as given below.
Numeric size | Category |
---|---|
0–2 | XS |
4–6 | S |
8–10 | M |
12–14 | L |
16–18 | XL |
20 | XXL |
22 | XXXL |
Implement the above table as a guarded equation.
:exercise: A quadratic equation can be written in the general form
\[ax^2 + bx + c = 0\]where $a,b,c$ are real numbers with $a \neq 0$. The solution(s) to a quadratic equation depends on the value of the discriminant $\Delta = b^2 - 4ac$. In particular, we have the following cases:
Write a guarded equation to determine the type of solutions of a given quadratic equation.
:exercise:
Write a Haskell function that outputs the body mass index given an adult’s
weight (kilogram) and height (metre). Use your implementation to test the
function weightStatus
from the section Body mass index.
:exercise: Using guarded equation, write a function for each of the following.
A recurring salesman from Horrible History. See him in action here. ↩