4.12. Conditionals

Guards are Morloc’s conditional branching. A guard clause starts with ?, followed by a condition and a result. A : default closes the chain and is always required:

abs :: Int -> Int
abs x
  ? x >= 0 = x
  : neg x       -- `neg` is negation, from root
$ ./guards abs -5
5

Conditions are evaluated lazily from top to bottom. The first one that is true decides the result, and the rest are never evaluated. Because the : default always terminates the chain, a guard is exhaustive by construction — there is no way to write one that falls off the end.

Guards work with any number of parameters:

clamp :: Int -> Int -> Int -> Int
clamp lo hi x
  ? x < lo = lo
  ? x > hi = hi
  : x
$ ./guards clamp 0 10 42
10

4.12.1. Guards with where

A where clause can supply bindings used in both the conditions and the results:

classify :: Int -> Str
classify x
  ? x > big = "big"
  ? x > small = "medium"
  : "small"
  where
    big = 100
    small = 10
$ ./guards classify 150
"big"
$ ./guards classify 50
"medium"
$ ./guards classify 5
"small"

4.12.2. Guards in other positions

A guard may be the body of a let binding:

absLet :: Int -> Int
absLet x =
  let result ? x >= 0 = x
             : neg x
  in result

and it may appear inline anywhere a value is expected. Parentheses are optional but usually clearer:

labelOf :: Int -> Str
labelOf x = "label: " <> (? x > 0 = "pos" : "non-pos")
$ ./guards labelOf 4
"label: pos"
$ ./guards labelOf -4
"label: non-pos"

4.12.3. Guards inside a pattern clause

Guards compose with refutable pattern matching (Pattern Matching). A |-clause may use a guard as its body, so one definition can match on an argument’s shape and then branch on a condition. Variables bound by the clause pattern are in scope in the guard:

sign :: Int -> Str
sign | 0 = "zero"                -- literal pattern matches only 0
     | x ? x < 0  = "neg"        -- otherwise bind x, then guard on it
         ? x < 10 = "small"
         : "large"
$ ./guards sign 0
"zero"
$ ./guards sign -2
"neg"
$ ./guards sign 5
"small"
$ ./guards sign 500
"large"