Prev: The Identity monad TOC: Contents Next: The Error monad

The Maybe monad


Overview

Computation type: Computations which may return Nothing
Binding strategy: Nothing values bypass the bound function, other values are used as inputs to the bound function.
Useful for: Building computations from sequences of functions that may return Nothing. Complex database queries or dictionary lookups are good examples.
Zero and plus: Nothing is the zero. The plus operation returns the first non-Nothing value or Nothing is both inputs are Nothing.
Example type: Maybe a

Motivation

The Maybe monad embodies the strategy of combining a chain of computations that may each return Nothing by ending the chain early if any step produces Nothing as output. It is useful when a computation entails a sequence of steps that depend on one another, and in which some steps may fail to return a value.

If you ever find yourself writing code like this:

case ... of
  Nothing -> Nothing
  Just x  -> case ... of
               Nothing -> Nothing
               Just y  -> ...
you should consider using the monadic properties of Maybe to improve the code.

Definition

data Maybe a = Nothing | Just a

instance Monad Maybe where
    return         = Just
    fail           = Nothing
    Nothing  >>= f = Nothing
    (Just x) >>= f = f x
    
instance MonadPlus Maybe where
    mzero             = Nothing
    Nothing `mplus` x = x
    x `mplus` _       = x

Example

A common example is in combining dictionary lookups. Given a dictionary that maps full names to email addresses, another that maps nicknames to email addresses, and a third that maps email addresses to email preferences, you could create a function that finds a person's email preferences based on either a full name or a nickname.

Code available in example11.hs
data MailPref = HTML | Plain
data MailSystem = ...
 
getMailPrefs :: MailSystem -> String -> Maybe MailPref
getMailPrefs sys name =
  do let nameDB = fullNameDB sys
         nickDB = nickNameDB sys
         prefDB = prefsDB sys
  addr <- (lookup name nameDB) `mplus` (lookup name nickDB)
  lookup addr prefDB

Prev: The Identity monad TOC: Contents Next: The Error monad