if, guards, and pattern guards

Contents
Guards
otherwise is a value
Pattern guards
When to use which

Guards

A guard is a condition written between the arguments and the equals sign. GHC tries the equations from top to bottom and uses the first one whose guard is true:

grade :: Int -> String grade n | n >= 90 = "A" | n >= 75 = "B" | n >= 60 = "C" | otherwise = "F"

The same logic as nested if expressions occupies half the lines and reads as a table. Order is the logic: the first matching guard wins, so the strongest condition goes first.

otherwise is a value

otherwise is not syntax. It is an ordinary name bound to True in the standard library, which is why it works as a catch-all:

otherwise :: Bool otherwise = True

A function whose guards all fail raises a pattern match failure at runtime. The compiler cannot prove that your conditions cover every input, so the catch-all guard is your promise that they do.

Pattern guards

A guard may also match a pattern. When the pattern fails, the guard is skipped, which makes lookups read without a case:

describe :: Maybe Int -> String describe m | Just n <- m, n > 0 = "positive " ++ show n | Just _ <- m = "not positive" | otherwise = "nothing"

Commas separate several conditions, and all of them must hold. A failed pattern short-circuits the rest, so n is safe to use in the following conditions.

When to use which

Use if for a single binary choice inside a larger expression. Use guards for a table of conditions on the arguments. Use case when the shape of a value decides the branch, and lesson 11 covers that next.

abs2 n = if n < 0 then negate n else n sign n | n < 0 = -1 | n > 0 = 1 | otherwise = 0

Mixing the three styles in one function is where readability dies. Pick the one that matches the shape of the decision and stay with it to the end of the function.

Next: case expressions

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: