New offer! Get 30% off one whole year of Unlimited learning. Subscribe for just £249.99 £174.99. New subscribers only. T&Cs apply

# Guards, Guards!

There are several elegant ways to define functions in Haskell. In this article, Dr Jeremy Singer explores guards and case expressions.

Haskell provides a notation for defining functions based on predicate values.

f x | predicate1 = expression1 | predicate2 = expression2 | predicate3 = expression3

For instance, the absolute value of a number is its magnitude, i.e. ignoring its sign.
You could define a function to calculate the absolute value
with an if/then/else conditional

absolute x = if (x<0) then (-x) else x

or with guards

absolute x | x<0 = -x | otherwise = x

Notice how there is no equals sign on the first line
of the function definition — but there is an equals sign
after each guard.

The otherwise guard should always be last, it’s like the
default case in a C-style switch statement.

Guards are easier to read than if/then/else if there are
more than two conditional outcomes

For instance, think about scoring in the sport of Golf. For a single
hole, a player takes a number of strokes. There is a
‘par’ score for the hole, which is the expected number of
strokes.

holeScore :: Int -> Int -> StringholeScore strokes par | strokes < par = show (par-strokes) ++ " under par" | strokes == par = "level par" | strokes > par = show(strokes-par) ++ " over par"

How could we tidy this up?
Maybe we could turn the final guard into otherwise
and also refactor with a where clause.

holeScore :: Int -> Int -> StringholeScore strokes par | score < 0 = show (abs score) ++ " under par" | score == 0 = "level par" | otherwise = show(score) ++ " over par" where score = strokes-par

Notice that the score variable defined in the where clause is in
scope for all three guards.

### Case expressions

Recall from last week how we defined algebraic data types
like binary trees. A value with an algebraic data type may have one of
several different forms — such as a Leaf or a Node, in the case of
Tree structures. Therefore to process such a value we need several
segments of code, one for each possible form.
The case expression examines the value, and chooses the corresponding
clause. It’s like a guard, but it selects based on
the form of the value, i.e. it does pattern matching.

Here is a sum data type for my pets.

data Pet = Cat | Dog | Fish

And here is how I greet my pets.

hello :: Pet -> Stringhello x =  case x of Cat -> "meeow" Dog -> "woof" Fish -> "bubble"

Note that each pattern is followed by an arrow and then a value.
Also note that each pattern is vertically aligned. Indentation

OK, now suppose we want to make the data type a bit more sophisticated .
Let’s add a Parrot with a String name.

data Pet = Cat | Dog | Fish | Parrot Stringhello :: Pet -> Stringhello x =  case x of Cat -> "meeow" Dog -> "woof" Fish -> "bubble" Parrot name -> "pretty " ++ name

Now the pattern includes a variable, which is
associated with the concrete value for the
Parrot’s name.

hello (Parrot "polly")

will return

"pretty polly"

In the same way as there is a catch-all case for guards (otherwise),
we can have a catch-all pattern for a case.
It’s the underscore character, _ which means ‘don’t care’ or ‘match anything’

So we could redefine hello as:

hello :: Pet -> Stringhello x = case x of Parrot name -> "pretty " ++ name _ -> "grunt"

How would you rewrite an if expression as a case expression?
In fact, this is what happens in the core language. The if expression is just syntactic sugar that is rewritten automatically. Can you think of any more examples of syntactic sugar in Haskell? Please add your thoughts in the comments section below.