Maybe and null safety

Contents
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

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: