Monad
Overview
monads: you apply a function that returns a wrapped value, to a wrapped value using >>= or liftM
The name monad is borrowed from category theory.
A monad is an algebraic structure similar to a #Monoids
Monads have been popularized in functional programming via the work of Moggi and Wadler.
Monad class
code:monadclass.hs
class Monad m where
-- Takes a monad (m a), with a function that returns a monad (a -> m b)
-- with these two, returns a monad in which the function is applied (m b)
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
Monadic operations
Several advantages to identifying the monad interface:
Have to learn fewer names. Same return and (>>=) (and do notation) in many different situations.
Useful derived functions that only use return and (>>=). All these library functions become automatically
available for every monad.
There are many more monads than the ones we’ve discussed so far. Monads can be combined to form new monads.
do notation
The do notation we is available for all monads:
code:do-notation.hs
foo :: Maybe String
foo = Just 3 >>= (\x ->
Just "!" >>= (\y ->
Just (show x ++ y)))
foo :: Maybe String
foo = do
x <- Just 3
y <- Just "!"
Just (show x ++ y)
Useful monad operations
More details on Control.Monad
code:operations.hs
liftM :: Monad m => (a -> b) -> m a -> m b
mapM :: Monad m => (a -> m b) -> a -> m b
mapM_ :: Monad m => (a -> m b) -> a -> m ()
forM :: Monad m => a -> (a -> m b) -> m b
forM_ :: Monad m => a -> (a -> m b) -> m ()
sequence :: Monad m => m a -> m a
sequence_ :: Monad m => m a -> m ()
forever :: Monad m => a -> m b
filterM :: Monad m => (a -> m Bool) -> a -> m a
replicateM :: Monad m => Int -> m a -> m a
replicateM_ :: Monad m => Int -> m a -> m ()
when :: Monad m => Bool -> m () -> m ()
unless :: Monad m => Bool -> m() -> m ()
code:actions.hs
(<$>) :: Monad m => (a -> b) -> m a -> m b
(>>) :: Monad m => m a -> m b -> m b
(<*>) :: Monad m => m (a -> b) -> m a -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Functor and Applicative in terms of Monad
Once Monad instance has been defined, one can use liftM and ap to define Applicatives and Functors. By doing you'll only need to Monad instance in order to use do notation.
code:applicative-functor.hs
instance Functor T where
fmap = liftM
instance Applicative T where
pure = return
(<*>) = ap
Lesson
The abstraction of monads is useful for a multitude of different types.
Monads can be seen as tagging computations with effects.
While IO is impure and cannot be defined in Haskell, the other effects we have seen can be modelled in a pure way:
exceptions via Maybe or Either ;
state via State ;
nondeterminism via []
The monad interface offers a large number of useful abstractions that can all be applied to these different scenarios.
All monads are also applicative functors and in particular functors. The (<$>) and (<*>) operations are also useful for structuring effectful code in Haskell.
List of monads
Maybe
(>>=) sequences operations that may fail and shortcuts evaluation once failure occurs;
return embeds a function that never fails;
State
(>>=) sequences operations that may modify some state and threads the state through the operations;
return embeds a function that never modifies the state;
List
(>>=)sequences operations that may have multiple results and executes subsequent operations for each of the previous results;
return embeds a function that only ever has one result.
IO
(>>=)sequences the side effects to the outside
return embeds a function without any side effects.
Reader
State
Maybe
Either
IO
Laws
Functor
code:functor:hs
fmap id x = x
fmap (f . g) x = (fmap f . fmap g) x
Applicative
code:applicative.hs
pure id <*> b = b
pure f <*> pure x = pure (f x)
a <*> pure x = pure ($ x) <*> a
pure (.) <*> a <*> b <*> c = a <*> (b <*> c)
Monad
code:monadlaw.hs
return x >>= f = f x
a >>= return = a
(a >>= f) >>= g = a >>= (\ x -> f x >>= g)
Useful features
Alternative
Monad transformer
Useful links
Functors, Applicatives, And Monads In Pictures