Maybe and null safety
| Why a missing value is a type | |
| Building and unwrapping | |
| fromMaybe and friends | |
| Chaining lookups |
Why a missing value is a type
There is no null in Haskell. A value that may be absent is written with a type that says so, and the compiler refuses to use it without handling the empty case:
data Maybe a = Nothing | Just a
findUser :: Int -> Maybe String
findUser 1 = Just "Ada"
findUser _ = Nothing
Maybe String means a string or nothing. Compare that with a signature of String, where the absence has to be smuggled in as an empty string or a magic value.
Building and unwrapping
Wrap with Just, and unwrap with pattern matching or case. Both branches are mandatory, which is the whole point:
greet :: Maybe String -> String
greet (Just name) = "Hello, " ++ name
greet Nothing = "Hello, stranger"
-- greet (Just "Ada") == "Hello, Ada"
A pattern match that forgets Nothing produces a non-exhaustive warning under -Wall and an exception at runtime, so the compiler pushes you towards handling it.
fromMaybe and friends
Three standard functions cover the common ways to leave the wrapper behind. All of them are total:
fromMaybe 0 (Just 5) -- 5
fromMaybe 0 Nothing -- 0
maybe "none" show (Just 5) -- "5"
isJust (Just 5) -- True
fromMaybe needs the import Data.Maybe. Reach for it when a sensible default exists, and keep the wrapper when the caller must decide.
Chaining lookups
Two lookups in a row would nest two cases. The >>= operator flattens the chain and short-circuits on the first Nothing:
cityOf :: Int -> Maybe String
cityOf uid =
findUser uid >>= \name ->
lookup name phoneBook
If findUser returns
Nothing, the lambda never runs and the result
is Nothing. Lesson 31 explains why this works
for every monad, not only for Maybe.
Next:
Either and recoverable errors
Article author: Arthur Isaev