Monads
A monad is a data type of composable actions. Monad is the class of type constructors whose values represent such actions. Perhaps IO is the most recognizable one: a value of IO a is a “recipe for retrieving an a value from the real world”.
We say a type constructor m (such as [] or Maybe) forms a monad if there is an instance Monad m satisfying certain laws about composition of actions. We can then reason about m a as an “action whose result has type a”.
No general way to extract value from a monadic computation
Section titled “No general way to extract value from a monadic computation”You can wrap values into actions and pipe the result of one computation into another:
return :: Monad m => a -> m a(>>=) :: Monad m => m a -> (a -> m b) -> m bHowever, the definition of a Monad doesn’t guarantee the existence of a function of type Monad m => m a -> a.
That means there is, in general, no way to extract a value from a computation (i.e. “unwrap” it). This is the case for many instances:
extract :: Maybe a -> aextract (Just x) = x -- Sure, this works, but...extract Nothing = undefined -- We can’t extract a value from failure.Specifically, there is no function IO a -> a, which often confuses beginners; see this example.
Monad as a Subclass of Applicative
Section titled “Monad as a Subclass of Applicative”As of GHC 7.10, Applicative is a superclass of Monad (i.e., every type which is a Monad must also be an Applicative). All the methods of Applicative (pure, <*>) can be implemented in terms of methods of Monad (return, >>=).
It is obvious that pure and return serve equivalent purposes, so pure = return. The definition for <*> is too relatively clear:
mf <*> mx = do { f <- mf; x <- mx; return (f x) } -- = mf >>= (\f -> mx >>= (\x -> return (f x))) -- = [r | f <- mf, x <- mx, r <- return (f x)] -- with MonadComprehensions -- = [f x | f <- mf, x <- mx]This function is defined as ap in the standard libraries.
Thus if you have already defined an instance of Monad for a type, you effectively can get an instance of Applicative for it “for free” by defining
instance Applicative < type > where pure = return (<*>) = apAs with the monad laws, these equivalencies are not enforced, but developers should ensure that they are always upheld.
Definition of Monad
Section titled “Definition of Monad”class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m bThe most important function for dealing with monads is the bind operator >>=:
(>>=) :: m a -> (a -> m b) -> m b- Think of
m aas “an action with anaresult”. - Think of
a -> m bas “an action (depending on anaparameter) with abresult.”.
>>= sequences two actions together by piping the result from the first action to the second.
The other function defined by Monad is:
return :: a -> m aIts name is unfortunate: this return has nothing to do with the return keyword found in imperative programming languages.
return x is the trivial action yielding x as its result. (It is trivial in the following sense:)
return x >>= f ≡ f x -- “left identity” monad law x >>= return ≡ x -- “right identity” monad lawThe Maybe monad
Section titled “The Maybe monad”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 Inthalve x | even x = Just (x `div` 2) | odd x = NothingThink 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 }takeOneEighthis a sequence of threehalvesteps chained together.- If a
halvestep fails, we want the whole compositiontakeOneEighthto fail. - If a
halvestep 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 xand now we can write:
takeOneEighth :: Int -> Maybe InttakeOneEighth 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 $ xKleisli 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 InttakeOneEighth = 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 x2. m >>= return = m3. (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 x2. f >=> return = f -- do { y <- f x ; return y } == f x3. (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.
- The left identity law -
return x >>= f = f x
return z >>= f= (Just z) >>= f= f z- The right identity law -
m >>= return = m
Justdata constructor
Just z >>= return= return z= Just zNothingdata constructor
Nothing >>= return= Nothing- The associativity law -
(m >>= f) >>= g = m >>= (\x -> f x >>= g)
Justdata 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 >>= gNothingdata constructor
-- Left-hand side(Nothing >>= f) >>= g= Nothing >>= g= Nothing
-- Right-hand sideNothing >>= (\x -> f x >>= g)= NothingIO monad
Section titled “IO monad”There is no way to get a value of type a out of an expression of type IO a and there shouldn’t be. This is actually a large part of why monads are used to model IO.
An expression of type IO a can be thought of as representing an action that can interact with the real world and, if executed, would result in something of type a. For example, the function getLine :: IO String from the prelude doesn’t mean that underneath getLine there is some specific string that I can extract - it means that getLine represents the action of getting a line from standard input.
Not surprisingly, main :: IO () since a Haskell program does represent a computation/action that interacts with the real world.
The things you can do to expressions of type IO a because IO is a monad:
-- print the lines "Hello" then "World" to stdout putStrLn "Hello" >> putStrLn "World" -- get a line from stdin and print it back out getLine >>= putStrLn -- make an action that just returns 5 return 5More from the Haskell Wiki on the IO monad here.
List Monad
Section titled “List Monad”The lists form a monad. They have a monad instantiation equivalent to this one:
sumnd xs ys = do x <- xs y <- ys return (x + y)Or equivalently, using liftM2 in Control.Monad:
sumnd = liftM2 (+)we obtain:
> sumnd [1,2,3] [0,10][1,11,2,12,3,13]do-notation
Section titled “do-notation”do-notation is syntactic sugar for monads. Here are the rules:
example :: IO Integerexample = putStrLn "What's your name?" >> ( getLine >>= (\name -> putStrLn ("Hello, " ++ name ++ ".") >> ( putStrLn "What should we return?" >> ( getLine >>= (\line -> let n = (read line :: Integer) in return (n + n))))))example :: IO Integerexample = do putStrLn "What's your name?" name <- getLine putStrLn ("Hello, " ++ name ++ ".") putStrLn "What should we return?" line <- getLine let n = (read line :: Integer) return (n + n)