[Haskell] Monad

class Monad m where
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

Monad Law
(1)return x >>= f = f x
(2)m >>= return = m
(3)(m >>= f) >>= g = m >>= (\x -> f x >>= g)

注:
(1):k m = * -> *
(2)在do notation中模式匹配失败后,程序并不会crash,而是会调用函数fail。
(3)m a类型的值,称为monad value。

(1)Maybe是Monad类型类的实例

instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
fail _ = Nothing

我们看一下>>=是如何实例化的

(>>=) :: m a -> (a -> m b) -> m b
= Maybe a -> (a -> Maybe b) -> Maybe b

ghci> Just 9 >= \x -> return (x * 10)
Just 90

ghci> Nothing >>= \x -> return (x * 10)
Nothing

注:do notation

ghci> Just 3 >>= \x -> Just “!” >>= \y -> Just (show x ++ y)
Just “3!”

其中,

Just 3 >>= \x -> Just “!” >>= \y -> Just (show x ++ y)
= Just 3 >>= \x -> (Just “!” >>= \y -> Just ((show x) ++ y))
= Just 3   >>= \x ->
   Just “!” >>= \y ->
   Just (show x ++ y)
= do
   x <- Just 3
   y <- Just “!”
   Just (show x ++ y)

注:
(1)do表达式的结果是一个monad value。
(2)在do表达式中,如果某一行我们没有使用“<-”为monad value绑定值,就相当于使用了函数“>>”,表示不需要这个绑定值。((>>) :: x >> y = x >>= \_ -> y

do
    Just 1
    x <- Just 2
    Just x
= Just 1 >> Just 2 >>= \x -> Just x
= Just 1 >>= \_ -> Just 2 >>= \x -> Just x

(2)[]是Monad类型类的实例

instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
ghci> [1,2] >>= \n -> ['a','b'] >>= \ch -> return (n, ch)
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]

推导如下:

[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n, ch)
= concat $ map (\n -> ['a','b'] >>= \ch -> return (n, ch)) [1, 2]

(\n -> ['a','b'] >>= \ch -> return (n, ch)) 1
= ['a','b'] >>= \ch -> return (1, ch)
= concat $ map (\ch -> return (1, ch)) ['a','b']

(\ch -> return (n, ch)) 'a'
= return (1, 'a')
= [(1, 'a')]    (自动推导出类型`[(Int,Char)]`)

concat $ map (\ch -> return (1, ch)) ['a','b']
= concat [[(1, 'a')], [(1, 'b')]]
= [(1, 'a'), (1, 'b')]

concat $ map (\n -> ['a','b'] >>= \ch -> return (n, ch)) [1, 2]
= concat [[(1, 'a'), (1, 'b')], [(2, 'a'), (2, 'b')]]
= [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

写成do notation如下:

[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n, ch)
= do
n <- [1, 2]
ch <- ['a','b']
return (n, ch)

注: list comprehension

ghci> [(n, ch) | n <- [1, 2], ch <- ['a','b']]
[(1,'a'),(1,'b'),(2,'a'),(2,'b')]

所以,list comprehension只是do notation的语法糖。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容