Guards vs. if-then-else vs. cases in Haskell

From a technical standpoint, all three versions are equivalent.

That being said, my rule of thumb for styles is that if you can read it as if it was English (read | as “when”, | otherwise as “otherwise” and = as “is” or “be”), you’re probably doing something right.

if..then..else is for when you have one binary condition, or one single decision you need to make. Nested if..then..else-expressions are very uncommon in Haskell, and guards should almost always be used instead.

let absOfN =
  if n < 0 -- Single binary expression
  then -n
  else  n

Every if..then..else expression can be replaced by a guard if it is at the top level of a function, and this should generally be preferred, since you can add more cases more easily then:

abs n
  | n < 0     = -n
  | otherwise =  n

case..of is for when you have multiple code paths, and every code path is guided by the
structure of a value, i.e. via pattern matching. You very seldom match on True and False.

case mapping of
  Constant v -> const v
  Function f -> map f

Guards complement case..of expressions, meaning that if you need to make complicated decisions depending on a value, first make decisions depending on the structure of your input, and then make decisions on the values in the structure.

handle  ExitSuccess = return ()
handle (ExitFailure code)
  | code < 0  = putStrLn . ("internal error " ++) . show . abs $ code
  | otherwise = putStrLn . ("user error " ++)     . show       $ code

BTW. As a style tip, always make a newline after a = or before a | if the stuff after the =/| is too long for one line, or uses more lines for some other reason:

-- NO!
nthElement (x:xs) a | a <= 0 = Nothing
                    | a == 1 = Just x
                    | a > 1 = nthElement xs (a-1)

-- Much more compact! Look at those spaces we didn't waste!
nthElement (x:xs) a
  | a <= 0    = Nothing
  | a == 1    = Just x
  | otherwise = nthElement xs (a-1)

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)