Pattern Matching, Guards and Local Bindings
6.1 Pattern Matching
Enable -Wall (or -Wincomplete-patterns) so GHC warns about non-exhaustive patterns.
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)
isEmpty :: [a] -> Bool
isEmpty [] = True
isEmpty _ = False -- _ is a wildcard
firstTwo :: [a] -> Maybe (a, a)
firstTwo (x : y : _) = Just (x, y)
firstTwo _ = Nothing
addPairs :: (Int, Int) -> (Int, Int) -> (Int, Int)
addPairs (a, b) (c, d) = (a + c, b + d)
describeList :: [a] -> String
describeList xs = case xs of
[] -> "empty"
[_] -> "singleton"
_ -> "longer list"
-- As-patterns
duplicateFirst :: [a] -> [a]
duplicateFirst all'@(x : _) = x : all'
duplicateFirst [] = []6.2 Guards
bmiCategory :: Double -> String
bmiCategory bmi
| bmi < 18.5 = "underweight"
| bmi < 25.0 = "normal"
| bmi < 30.0 = "overweight"
| otherwise = "obese" -- otherwise = True
compareAges :: Int -> Int -> String
compareAges a b
| a > b = "older"
| a < b = "younger"
| otherwise = "same age"6.3 where and let
bmiReport :: Double -> Double -> String
bmiReport weight height
| bmi < 18.5 = "underweight (" ++ show bmi ++ ")"
| otherwise = "ok (" ++ show bmi ++ ")"
where
bmi = weight / height ^ 2 -- visible to all guards
cylinderArea :: Double -> Double -> Double
cylinderArea r h =
let sideArea = 2 * pi * r * h
topArea = pi * r ^ 2
in sideArea + 2 * topArea -- let ... in is an expression6.4 Extensions for Patterns
{-# LANGUAGE LambdaCase, MultiWayIf, ViewPatterns, BangPatterns #-}
classify :: Int -> String
classify = \case -- LambdaCase
0 -> "zero"
n | n < 0 -> "negative"
| otherwise -> "positive"
sign :: Int -> Int
sign n = if | n > 0 -> 1 | n < 0 -> -1 | otherwise -> 0 -- MultiWayIf
firstWord :: String -> String
firstWord (words -> (w : _)) = w -- ViewPatterns
firstWord _ = ""