Monad 是一个从 Applicative functors 很自然的一个演进结果。对于他们我们主要考量的点是:如果你有一个具有 context 的值 m a
,你能如何把他丢进一个只接受普通值 a
的函数中,并回传一个具有 context 的值?也就是说,你如何套用一个型态为 a -> m b
的函数至 m a
?基本上,我们要求的函数是:
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
如果我们有一个漂亮的值跟一个函数接受普通的值但回传漂亮的值,那我们要如何要把漂亮的值丢进函数中?这就是我们使用 Monad 时所要考量的事情。我们不写成 f a
而写成 m a
是因为 m
代表的是 Monad
,但 monad 不过就是支持 >>=
操作的 applicative functors。>>=
我们称呼他为 bind。
当我们有一个普通值 a
跟一个普通函数 a -> b
,要套用函数是一件很简单的事。但当你在处理具有 context 的值时,就需要多考虑些东西,要如何把漂亮的值喂进函数中,并如何考虑他们的行为,但你将会了解到他们其实不难。
class Monad m wherereturn 等价于
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> y
fail :: String -> m a
fail msg = error msg
pure. 型态是 (Monad m) => a -> m a.
并不是结束一个函数的执行,他只不过是把一个普通值包进一个 context 里面。
bind: >>=
。他就像是函数套用一样,只差在他不接受普通值,他是接受一个 monadic value(也就是具有 context 的值)
并且把他喂给一个接受普通值的函数,并回传一个 monadic value。
instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
fail _ = Nothing
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
ghci> [3,4,5] >>= \x -> [x,-x]
[3,-3,4,-4,5,-5]
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
instance MonadPlus [] whereMonadPlus 和 Monoid 很像
mzero = []
mplus = (++)
guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero
ghci> guard (5 > 2) :: Maybe ()
Just ()
ghci> guard (1 > 2) :: Maybe ()
Nothing
ghci> guard (5 > 2) :: [()]
[()]
ghci> guard (1 > 2) :: [()]
[]
ghci> guard (5 > 2) >> return "cool" :: [String]
["cool"]
ghci> guard (1 > 2) >> return "cool" :: [String]
[]
Monad laws (单子律)
*retrun x >>= f
应该等于
f x (
Left identity
)
*
m >>= return
会等于 m (Right identity)
* (m >>= f) >>= g 跟 m >>= (\x -> f x >>= g) 是相等的 (Associativity)
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = (\x -> f (g x))
如果 g
的型态是 a -> b
且 f
的型态是 b -> c
,我们可以把他们合成一个型态是 a -> c
的新函数。
所以中间的参数都有自动带过。现在假设这两个函数是 monadic function,也就是说如果他们的回传值是 monadic function?
如果我们有一个函数他的型态是 a -> m b
,我们并不能直接把结果丢给另一个型态为 b -> m c
的函数,
因为后者只接受型态为 b
的普通值。然而,我们可以用 >>=
来做到我们想要的事。有了 >>=
,
我们可以合成两个 monadic function:
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = (\x -> g x >>= f)
合成的定律:f <=< (g <=< h)
跟(f <=< g) <=< h
应该等价
do 表示法
foo :: Maybe String
foo = Just 3 >>= (\x ->
Just "!" >>= (\y ->
Just (show x ++ y)))
foo :: Maybe String如果我们拿到一个
foo = do
x <- Just 3
y <- Just "!"
Just (show x ++ y)
Maybe String
,并用
<-
来绑定给一个变量,那个变量就会是一个
String
,