Maybe is used to represent possibly empty values - similar to null in other languages. Usually it is used as the output type of functions that can fail in some way.
Consider the following function:
halve :: Int -> Maybe Int
halve x
| even x = Just (x `div` 2)
| odd x = Nothing
Think of halve as an action, depending on an Int, that tries to halve the integer, failing if it is odd.
How do we halve an integer three times?
takeOneEighth :: Int -> Maybe Int -- (after you read the 'do' sub-section:)
takeOneEighth x =
case halve x of -- do {
Nothing -> Nothing
Just oneHalf -> -- oneHalf <- halve x
case halve oneHalf of
Nothing -> Nothing
Just oneQuarter -> -- oneQuarter <- halve oneHalf
case halve oneQuarter of
Nothing -> Nothing -- oneEighth <- halve oneQuarter
Just oneEighth ->
Just oneEighth -- return oneEighth }
takeOneEighth is a sequence of three halve steps chained together.halve step fails, we want the whole composition takeOneEighth to fail.halve step succeeds, we want to pipe its result forward.instance Monad Maybe where
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= f = Nothing -- infixl 1 >>=
Just x >>= f = Just (f x) -- also, f =<< m = m >>= f
-- return :: a -> Maybe a
return x = Just x
and now we can write:
takeOneEighth :: Int -> Maybe Int
takeOneEighth x = halve x >>= halve >>= halve -- or,
-- return x >>= halve >>= halve >>= halve -- which is parsed as
-- (((return x) >>= halve) >>= halve) >>= halve -- which can also be written as
-- (halve =<<) . (halve =<<) . (halve =<<) $ return x -- or, equivalently, as
-- halve <=< halve <=< halve $ x
Kleisli composition <=< is defined as (g <=< f) x = g =<< f x, or equivalently as (f >=> g) x = f x >>= g. With it the above definition becomes just
takeOneEighth :: Int -> Maybe Int
takeOneEighth = halve <=< halve <=< halve -- infixr 1 <=<
-- or, equivalently,
-- halve >=> halve >=> halve -- infixr 1 >=>
There are three monad laws that should be obeyed by every monad, that is every type which is an instance of the Monad typeclass:
1. return x >>= f = f x
2. m >>= return = m
3. (m >>= g) >>= h = m >>= (\y -> g y >>= h)
where m is a monad, f has type a -> m b and g has type b -> m c.
Or equivalently, using the >=> Kleisli composition operator defined above:
1. return >=> g = g -- do { y <- return x ; g y } == g x
2. f >=> return = f -- do { y <- f x ; return y } == f x
3. (f >=> g) >=> h = f >=> (g >=> h) -- do { z <- do { y <- f x; g y } ; h z }
-- == do { y <- f x ; do { z <- g y; h z } }
Obeying these laws makes it a lot easier to reason about the monad, because it guarantees that using monadic functions and composing them behaves in a reasonable way, similar to other monads.
Let's check if the Maybe monad obeys the three monad laws.
return x >>= f = f xreturn z >>= f
= (Just z) >>= f
= f z
m >>= return = mJust data constructorJust z >>= return
= return z
= Just z
Nothing data constructorNothing >>= return
= Nothing
(m >>= f) >>= g = m >>= (\x -> f x >>= g)Just data constructor-- Left-hand side
((Just z) >>= f) >>= g
= f z >>= g
-- Right-hand side
(Just z) >>= (\x -> f x >>= g)
(\x -> f x >>= g) z
= f z >>= g
Nothing data constructor-- Left-hand side
(Nothing >>= f) >>= g
= Nothing >>= g
= Nothing
-- Right-hand side
Nothing >>= (\x -> f x >>= g)
= Nothing