What is Monad?

When M is a monad, values of type M X are operations that can be executed to produce a value of type X.

1
2
3
4
5
6
7
8
9
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b

-- lift a normal value into the monad
return :: a -> m a

-- simpler chaining (like our ##>)
(>>) :: m a -> m b -> m b
a >> b = a >>= \_ -> b -- remember: _ means ignored argument

可以把数据类型视为一个盒子,Monad 相当于是,一个可能执行起来可能有副作用的函数 f :: a -> m bm 就是 Haskell 里对 side-effects 的建模处理),接受一个盒子里的值 m a,从盒子里取出值后进行运算再放回盒子

Maybe 其实也是 Monad

1
2
3
4
5
6
7
8
instance  Monad Maybe  where
(Just x) >>= k = k x
Nothing >>= _ = Nothing

(Just _) >> k = k
Nothing >> _ = Nothing

return x = Just x

do block 的语法和 Monad 其实是很类似的:

1
2
3
4
do x <- op a
...
-- equiv to
op a >>= \_ -> do ...
1
2
3
do op a
-- equiv to
op a >> do
1
2
3
do let x = expr
-- equiv
let x = expr in do ...
1
2
3
do finalOp
-- equiv to
finalOp

实现 Monad

在实现 Monad 之前,必须先实现 ApplicativeFunctor

State Monad

The State Monad

State 有两个类型参数,第一个是状态类型,第二个是计算结果类型,需要从 transformers package 的 Control.Monad.Trans.State 引入

State Monad 可以这样理解:我们通过定义 someFunc :: a -> State a () 定义操作,然后再通过 runState (someFunc arguments) initValue 或者 execState 获取最后的操作结果.其相对于直接 foldl/foldr 方式的优点在于,因为 someFunc 的函数定义体里肯定会有 modify, get, put 这类对 State s a 的操作,所以可以同时用 a 记录额外信息,不需要在 foldl/foldr 的参数里添加额外的参数用来记录了.

Return of mapM

一些函数对于 Monad 也是有效的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- conditional operation
when :: Monad m => Bool -> m () -> m ()

-- same, but condition is flipped
unless :: Monad m => Bool -> m () -> m ()

-- do something many times
replicateM :: Monad m => Int -> m a -> m [a]

-- same, but ignore the results
replicateM_ :: Monad m => Int -> m a -> m ()

-- do something on a list's elements
mapM :: Monad m => (a -> m b) -> [a] -> m [b]

-- same, but ignore the results
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

-- mapM but arguments reversed
forM :: Monad m => [a] -> (a -> m b) -> m [b]

-- same, but ignore the results
forM_ :: Monad m => [a] -> (a -> m b) -> m ()

Monads are Functors

另一个有用的函数

1
2
3
liftM :: Monad m => (a -> b) -> m a -> m b
liftM f op = do x <- op
return (f x)

[] List Monads

其表现类似于笛卡尔积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
do word <- ["Blue", "Green"]
number <- [1,2,3]
return (word ++ show number)
-- ==> ["Blue1","Blue2","Blue3","Green1","Green2","Green3"]

findSum :: [Int] -> Int -> [(Int,Int)]
findSum xs k = do a <- xs
b <- xs
if (a+b==k) then [(a,b)] else []

findSum [1,2,3,4,5] 5
-- ==> [(1,4),(2,3),(3,2),(4,1)]

-- 用 List Comprehesion 实现
findSum :: [Int] -> Int -> [(Int,Int)]
findSum xs k = [(a,b) | a <- xs, b <- xs, a+b==k ]