Skip main navigation
We use cookies to give you a better experience, if that’s ok you can close this message and carry on browsing. For more info read our cookies policy.
We use cookies to give you a better experience. Carry on browsing if you're happy with this, or read our cookies policy for more information.
Here be dragons

Example: the Maybe monad

  • We’ve already seen the Maybe type. Let’s look at the Maybe monad, which makes using the Maybe type a lot easier.

The Maybe type constructor

You already know the definition of the Maybe type:

    data Maybe a = Just a | Nothing

Example use of Maybe: Safe head and tail

The head and tail functions from the Prelude are not safe in the sense that they fail when called on an empty list. We can define safe versions using Maybe:

    myHead :: [a] -> Maybe a
    myHead [] = Nothing
    myHead (x:xs) = Just x

    myTail :: [a] -> Maybe [a]
    myTail [] = Nothing
    myTail (x:xs) = Just xs

Monad instance of Maybe

Now we can make Maybe an instance of the Monad type class, simply by providing the appropriate definitions for return, bind, then and fail:

    import Control.Monad

    instance Monad Maybe where
        return           =   Just
        Nothing  >>= f = Nothing
        (Just x) >>= f = f x
        fail _           =   Nothing

There are a few additional functions defined in the MonadPlus type class:

    instance MonadPlus Maybe where
        mzero               = Nothing
        Nothing `mplus` x = x
        x `mplus` _         = x

That’s it, we now have a Maybe monad!

Note: for users of ghc 7.10 and higher, we need to do a little bit more work.

Explicit Maybe versus the Maybe Monad

Let’s see what this monad gives us:

A computation using explicit Maybe

    foo :: [a] -> Maybe a
    foo xs =
      case myTail xs of
        Nothing -> Nothing
        Just a -> case myTail a of
                    Nothing -> Nothing
                    Just b -> myHead b

To combine computations that use the Maybe type, we need explicit case expressions to pattern match against the type.

A computation using the Maybe monad

Let’s write this computation using the Maybe monad, first using the >>= operator:

    bar :: [a] -> Maybe a
    bar xs =
      myTail xs >>=
        (\a -> myTail a >>=
          (\b -> myHead b))

Now let’s change the line breaks and indentation a bit to make it look nicer:

    bar2 :: [a] -> Maybe a
    bar2 xs =
      myTail xs >>= (\a ->
      myTail a >>=  (\b ->
      myHead b))

Thanks to the associativity law, we can also remove unnecessary parentheses:

    bar3 :: [a] -> Maybe a
    bar3 xs =
      myTail xs >>= \a ->
      myTail a >>=  \b ->
      myHead b

This is already a lot cleaner, but finally we can use the do-notation:

    bar3 :: [a] -> Maybe a
    bar3 xs = do
      a <- myTail xs
      b <- myTail a
      myHead b

Clearly, the final monadic code is a lot more readable than the original non-monadic code.

Example: Reduction of bar [5,6]

        bar [5,6]

    -- > substitute [5,6] for xs in definition of bar

        myTail [5,6] >>=
         (\a -> myTail a >>=
          (\b -> myHead b))

    -- > def. myTail

        Just [6]  >>=
         (\a -> myTail a >>=
          (\b -> myHead b))

    -- >  def.2 of (>>=)

         (\a -> myTail a >>=
          (\b -> myHead b))
            [6]
    -- > beta reduction, substitute [6] for a

         myTail [6] >>= (\b -> myHead b)

    -- > reduce myTail

         Just [] >>=  (\b -> myHead b)

    -- >  def.2 of (>>=)   

        (\b -> myHead b) []

    -- > beta reduction, substitute [] for b

       myHead []

    -- > def.1 myHead

      Nothing

Example: Reduction of bar [5,6,7]

        bar [5,6,7]

    -- > substitute [5,6,7] for xs in definition of bar

        myTail [5,6,7] >>=
         (\a -> myTail a >>=
          (\b -> myHead b))

    -- > def. myTail

        Just [6,7]  >>=
         (\a -> myTail a >>=
          (\b -> myHead b))

    -- >  def.2 of (>>=)

         (\a -> myTail a >>=
          (\b -> myHead b))
            [6,7]
    -- > beta reduction, substitute [6,7] for a

         myTail [6,7] >>= (\b -> myHead b)

    -- > reduce myTail

         Just [7] >>=  (\b -> myHead b)

    -- >  def.2 of (>>=)   

        (\b -> myHead b) [7]

    -- > beta reduction, substitute [7] for b

        myHead [7]

    -- > def myHead

        Just 7

Share this article:

This article is from the free online course:

Functional Programming in Haskell: Supercharge Your Coding

University of Glasgow

Get a taste of this course

Find out what this course is like by previewing some of the course steps before you join:

  • Brief History of Haskell
    Brief History of Haskell
    article

    What are the origins of the Haskell programming language? In this article, Dr Jeremy Singer explores the history of Haskell.

Contact FutureLearn for Support