Monad
Writer Monad
Writer 可以让我们在计算的同时搜集所有 log 纪录,并汇集成一个 log 并附加在结果上
applyLog :: (a,String) -> (a -> (b,String)) -> (b,String)
applyLog (x,log) f = let (y,newLog) = f x in (y,log ++ newLog)
ghci> (30, "A freaking platoon.") `applyLog` isBigGang
(True,"A freaking platoon.Compared gang size to 9")
ghci> ("BathCat","Got outlaw name.") `applyLog` (\x -> (length x, "Applied length"))
(7,"Got outlaw name.Applied length")
Control Monad Writer
instance (Monoid w) => Monad (Writer w) where
return x = Writer (x, mempty)
(Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v')
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber x = Writer (x, ["Got number: " ++ show x])
multiWithLog :: Writer [String] Int
multiWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a*b)
Reader Monad
instance Monad ((->) r) where
return x = _ -> x
h >>= f = \w -> f (h w) w
State Monad
Control Monad State
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State $ \s -> let (a, newState) = h s
(State g) = f a
in g newState
get = State $ \s -> (s,s)
put newState = State $ \s -> ((),newState)
State Monad Case
import Control.Monad.State
pop :: State Stack Int
pop = State $ \(x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = State $ \xs -> ((),a:xs)
stackManipulation :: State Stack Int
stackManipulation = do
push 3
a <- pop
pop
Error Monad
instance (Error e) => Monad (Either e) where
return x = Right x
Right x >>= f = f x
Left err >>= f = Left err
fail msg = Left (strMsg msg)
ghci> :t strMsg
strMsg :: (Error a) => String -> a
ghci> strMsg "boom!" :: String
"boom!"