Guarded equations for conditional expressions in Haskell

Sunday, Dec 6, 2020
Functional Haskell

Conditional expressions are fundamental programming constructs to choose a sub-expression based on a logical condition. if e then e1 else e2 is the most common syntax to accomplish this. Here e is the logical expression and the entire expression evaluates to e1 if e evaluates to True and e2 if e evaluates to False. Although semantically simple, it becomes hard to read for nested conditionals. For example, for a function to calculate discount based on the number of items purchased per the table below, we can write our code as follows:

# of items Discount
> 100 0.20
> 50 0.10
> 20 0.05
otherwise 0
getDiscount :: Fractional a => Int -> a
getDiscount n =
  if n > 100
  then 0.20
  else if n > 50
       then 0.10
       else if n > 20
            then 0.05
            else 0

Haskell provides an alternative syntax called guarded equations to make nested conditionals more concise and readable. Syntax is

f x | b1 = e1
    | b2 = e2
    ...

Here bi is a boolean expression which if evaluates to True, the entire function's result will be the result of evaluating ei. An optional catch all phrase is otherwise which is equivalent to True and thus is used for conditional in case every expression above it evaluates to False. It is used at the end of guarded equation. Let's see how our example above translated to guarded equation.

getDiscount2 :: Fractional a => Int -> a
getDiscount2 n | n > 100 = 0.20
               | n > 50 = 0.10
               | n > 20 = 0.05
               | otherwise = 0

Much better!