Guards in Haskell are a way to make decisions in your code based on boolean expressions. They are often used in function definitions to choose between different actions based on the values of the function's arguments. Guards provide a more readable and expressive way to handle multiple conditions compared to nested if-then-else
statements.
Key Concepts
-
Syntax of Guards:
- Guards are written using the pipe symbol (
|
). - Each guard is followed by a boolean expression.
- If the boolean expression evaluates to
True
, the corresponding result is returned. - An
otherwise
guard can be used as a catch-all condition.
- Guards are written using the pipe symbol (
-
Usage in Function Definitions:
- Guards are typically used in function definitions to handle different cases.
- They can be used to simplify complex conditional logic.
-
Order of Evaluation:
- Guards are evaluated from top to bottom.
- The first guard that evaluates to
True
will determine the result.
Practical Examples
Example 1: Simple Guard Usage
Let's define a function absolute
that returns the absolute value of a number using guards.
Explanation:
- The function
absolute
takes an integerx
as input. - The first guard checks if
x
is less than 0. If true, it returns-x
. - The
otherwise
guard is a catch-all that returnsx
if none of the previous guards are true.
Example 2: Grading System
Let's create a function grade
that assigns a letter grade based on a numerical score.
grade :: Int -> String grade score | score >= 90 = "A" | score >= 80 = "B" | score >= 70 = "C" | score >= 60 = "D" | otherwise = "F"
Explanation:
- The function
grade
takes an integerscore
as input. - It uses multiple guards to check the range of the score and returns the corresponding letter grade.
- The guards are evaluated in order, so the first matching condition determines the result.
Practical Exercises
Exercise 1: Max of Three
Write a function maxOfThree
that takes three integers and returns the maximum of the three using guards.
maxOfThree :: Int -> Int -> Int -> Int maxOfThree a b c | a >= b && a >= c = a | b >= a && b >= c = b | otherwise = c
Exercise 2: BMI Calculator
Write a function bmi
that calculates the Body Mass Index (BMI) and categorizes it into "Underweight", "Normal", "Overweight", or "Obese".
bmi :: Double -> Double -> String bmi weight height | bmiValue < 18.5 = "Underweight" | bmiValue < 24.9 = "Normal" | bmiValue < 29.9 = "Overweight" | otherwise = "Obese" where bmiValue = weight / (height * height)
Explanation:
- The function
bmi
takesweight
(in kilograms) andheight
(in meters) as inputs. - It calculates the BMI value using the formula
weight / (height * height)
. - Guards are used to categorize the BMI value into different weight categories.
Common Mistakes and Tips
- Order of Guards: Ensure that guards are ordered correctly. The first guard that evaluates to
True
will be the result, so more specific conditions should come before more general ones. - Boolean Expressions: Guards must be followed by boolean expressions. Ensure that each guard condition is a valid boolean expression.
- Catch-All Guard: Use
otherwise
as a catch-all guard to handle any cases not covered by previous guards.
Conclusion
Guards in Haskell provide a powerful and readable way to handle multiple conditions in your code. By using guards, you can simplify complex conditional logic and make your functions more expressive. Practice using guards in different scenarios to become comfortable with this feature of Haskell. In the next module, we will explore higher-order functions, which are a fundamental concept in functional programming.
Haskell Programming Course
Module 1: Introduction to Haskell
- What is Haskell?
- Setting Up the Haskell Environment
- Basic Syntax and Hello World
- Haskell REPL (GHCi)