Haskell 中的函子、应用函子、单子
2019/07/19
距离上次学习Haskell已经过去八个多月了,以前一起讨论的同事都跑路了,谨以此系列纪念我优秀的前同事们。。。
函子:(Functor) 是把一个普通的函数映射为盒子上的函数,或者说,可以把普通函数应用到盒子内的值,列表的fmap 就是 map。
fmap :: Functor f => (a -> b) -> f a -> f b
应用函子:(Applicative) 首先是个函子,额外提供如下俩操作
- 把普通值包裹为盒子值,比如普通的list作为应用函子时,pure a = [a]
pure :: Applicative f => a => f a
-
<*> (应用)是把盒子内的函数应用给另一个相同盒子内的值,比如
[\a->a+1, \a -> a * 2] <*> [1,2,3] 可以得到 [2,3,4,2,4,6]
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
单子:(Monad) 首先是个应用函子(尽管从历史上说,是先有的Monad后有的Applicative),额外提供如下bind操作,可以把一个单子 m a 喂给另一个 (a -> m b) 的函数,返回一个新的单子,比如 [1,2,3] >>= \x -> [x+1, x*2] = [2,2,3,4,4,6]
(>>=) :: Monad m => m a -> (a -> m b) -> m b
很多语言里的flatMap,在haskell中叫做 join ,可以把盒子的盒子,变成盒子类型。比如 join [[1],[2],[3]] = [1,2,3]
join :: Monad m => m (m a) -> m a
join x = x >>= id (想想为什么这么实现)
join
和 bind (>>=)
可以互相实现:
m >>= f = join (fmap f m)
所以在别的语言中,才会有「实现了flatMap就是Monad了」这种说法,从以上的描述看起来,这是不够严谨的,忽略了Monad同时也得是Functor,以及也要具有Applicative的操作,并且需要符合函子定律,应用函子定律和单子定律。