Monad
19.1 The Monad Class
A Monad lets the next computation depend on the result of the previous one. That's the key difference from Applicative.
class Applicative m => Monad m where
(>>=) :: m a -> (a -> m b) -> m b -- "bind"
return :: a -> m a -- same as pure
(>>) :: m a -> m b -> m b -- sequence, discarding the first result
-- Laws:
-- return a >>= f == f a (left identity)
-- m >>= return == m (right identity)
-- (m >>= f) >>= g == m >>= (\x -> f x >>= g) (associativity)19.2 do-Notation
-- These are equivalent:
example1 :: Maybe Int
example1 = safeDiv 100 5 >>= \x -> safeDiv x 2 >>= \y -> return (x + y)
example2 :: Maybe Int
example2 = do
x <- safeDiv 100 5 -- if Nothing, the whole block is Nothing
y <- safeDiv x 2
let z = x + y -- pure let binding inside do
return z -- Just 3019.3 Monad Instances in Action
-- Maybe: short-circuiting failure
lookupChain :: Maybe String
lookupChain = do
userId <- lookup "ana" [("ana", 1), ("bo", 2)]
lookup userId [(1, "ana@example.com")]
-- Either: failure with an error value
parseAge :: String -> Either String Int
parseAge s = do
n <- maybe (Left ("not a number: " ++ s)) Right (readMaybe s)
if n < 0 then Left "negative" else Right n
-- List: non-determinism (all possibilities)
pairsSum10 :: [(Int, Int)]
pairsSum10 = do
x <- [1 .. 9]
y <- [x .. 9]
if x + y == 10 then return (x, y) else []
-- [(1,9),(2,8),(3,7),(4,6),(5,5)]
import Control.Monad (guard)
knightMoves :: (Int, Int) -> [(Int, Int)]
knightMoves (c, r) = do
(dc, dr) <- [(1, 2), (2, 1), (-1, 2), (-2, 1), (1, -2), (2, -1), (-1, -2), (-2, -1)]
let (c', r') = (c + dc, r + dr)
guard (c' `elem` [1 .. 8] && r' `elem` [1 .. 8])
return (c', r')
-- Functions ((->) r): the Reader monad (Module 25)
addStuff :: Int -> Int
addStuff = do
a <- (* 2)
b <- (+ 10)
return (a + b)
-- addStuff 3 == 1919.4 Useful Monadic Functions (Control.Monad)
import Control.Monad
mapM print [1, 2, 3] -- run actions, collect results (traverse)
mapM_ print [1, 2, 3] -- run actions, discard results (traverse_)
forM_ [1 .. 3] $ \i -> print (i * i) -- flipped mapM_
replicateM 2 "ab" -- ["aa","ab","ba","bb"]
replicateM_ 3 (putStrLn "hi")
when True (putStrLn "printed")
unless False (putStrLn "also printed")
foldM (\acc x -> if x > 0 then Just (acc + x) else Nothing) 0 [1, 2, 3] -- Just 6
filterM (const [True, False]) [1, 2] -- powerset: [[1,2],[1],[2],[]]
zipWithM_ (\i s -> putStrLn (show i ++ ": " ++ s)) [1 ..] ["a", "b"]
join (Just (Just 3)) -- Just 3
forever (getLine >>= putStrLn) -- loop forever (until an exception)
-- (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c -- Kleisli composition
safeRoot = (\x -> if x < 0 then Nothing else Just (sqrt x)) >=> (\y -> Just (y * 2))