Skip to content
AgileLogics
5 min read

Conditionals: if and Guards

Prerequisites: Defining functions

if-then-else is an expression

In Haskell, if produces a value, like the ? : operator in C-style languages. That's why the else is required — the expression must have a value either way:

describe :: Int -> String
describe n = if n < 0 then "negative" else "non-negative"

main :: IO ()
main = do
  putStrLn (describe (-3))
  putStrLn (describe 5)
  print (if 10 > 3 then 1 else 0 + 100)
negative
non-negative
1

Both branches must have the same type — you can't return a String from one and an Int from the other.

Guards

For more than two cases, guards read much better than nested ifs. Each | is followed by a condition and the result if it's true, checked top to bottom:

classify :: Int -> String
classify n
  | n < 0 = "negative"
  | n == 0 = "zero"
  | n < 10 = "small"
  | otherwise = "large"

bmi :: Double -> Double -> String
bmi weight height
  | value < 18.5 = "underweight"
  | value < 25 = "normal"
  | otherwise = "overweight"
  where
    value = weight / height ^ 2

main :: IO ()
main = do
  mapM_ (putStrLn . classify) [-5, 0, 7, 42]
  putStrLn (bmi 70 1.75)
negative
zero
small
large
normal
  • otherwise is simply defined as True — a catch-all final guard.
  • where defines helper values that all guards can use (more on it in a later lesson).
  • mapM_ f list runs an action for every element of a list.

Comparison and logic operators

Operator Meaning
==, /= Equal, not equal (note /=, not !=)
<, <=, >, >= Ordering
&&, `
main :: IO ()
main = do
  print (3 /= 4, not True, True && False || True)
  print (compare 3 7, compare "b" "a", max "apple" "pear")
(True,False,True)
(LT,GT,"pear")

compare returns an Ordering: LT, EQ, or GT. Strings compare alphabetically.

Practice

Write fizzbuzz :: Int -> String with guards and print it for 1 to 15 using mapM_.

Show solution
fizzbuzz :: Int -> String
fizzbuzz n
  | n `mod` 15 == 0 = "FizzBuzz"
  | n `mod` 3 == 0 = "Fizz"
  | n `mod` 5 == 0 = "Buzz"
  | otherwise = show n

main :: IO ()
main = mapM_ (putStrLn . fizzbuzz) [1 .. 15]
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz