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
otherwiseguard 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
Truewill 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
absolutetakes an integerxas input. - The first guard checks if
xis less than 0. If true, it returns-x. - The
otherwiseguard is a catch-all that returnsxif 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
gradetakes an integerscoreas 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 = cExercise 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
bmitakesweight(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
Truewill 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
otherwiseas 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)
