पाठ 12 / 25
Monads and do Notation
Sequence dependent effects with >>= and do notation, and build a State monad.
Sequencing where each step depends on the last
Monad adds >>= ("bind"): m >>= k runs m, takes its result and passes it to k, which decides the next computation. This allows each step to depend on previous results, which Applicative cannot express. do notation is syntactic sugar for chains of >>=: x <- action binds a result, let binds pure values, and the last line is the result. Each monad gives >>= its own meaning: for Maybe and Either, stop at the first failure; for lists, try every possibility (non-determinism); for IO, perform effects in order; for State s, thread a state value through computations; for Reader r, share a read-only environment; for Writer w, accumulate a log. The monad laws (left identity, right identity and associativity) ensure that refactoring do blocks behaves predictably. Monads are not about side effects in general; they are a common interface for sequencing computations in a context. Building a small State monad by hand, as below, demystifies them; in practice, use Control.Monad.State from the mtl package.
A State monad from scratch
Functor, Applicative and Monad instances, then do notation.
newtype State s a = State { runState :: s -> (a, s) }
instance Functor (State s) where
fmap f (State g) = State $ \s -> let (a, s') = g s in (f a, s')
instance Applicative (State s) where
pure a = State $ \s -> (a, s)
State f <*> State g = State $ \s ->
let (h, s1) = f s
(a, s2) = g s1
in (h a, s2)
instance Monad (State s) where
State g >>= k = State $ \s ->
let (a, s1) = g s
in runState (k a) s1
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
freshOrderId :: State Int String
freshOrderId = do
n <- get
put (n + 1)
pure ("o-" ++ show n)
threeOrders :: State Int [String]
threeOrders = do
a <- freshOrderId
b <- freshOrderId
c <- freshOrderId
pure [a, b, c]
main :: IO ()
main = print (runState threeOrders 100) -- (["o-100","o-101","o-102"],103)An assembly line with a decision at each station
A monad is an assembly line where each station looks at what arrived and decides what the next station should do. The kind of line (Maybe, IO, State) decides the house rules: stop when a part is missing, carry a clipboard of state along, or actually press buttons in the real world.
त्वरित जाँच: What can Monad express that Applicative alone cannot?
- Computations where later steps depend on the results of earlier ones
- Pure values
- Mapping over lists
- Equality checks
Answer
Computations where later steps depend on the results of earlier ones — Bind passes each result to a function that chooses the next computation.