YSMull
<-- home

Haskell 中的函子、应用函子、单子

距离上次学习Haskell已经过去八个多月了,以前一起讨论的同事都跑路了,谨以此系列纪念我优秀的前同事们。。。

函子:(Functor) 是把一个普通的函数映射为盒子上的函数,或者说,可以把普通函数应用到盒子内的值,列表的fmap 就是 map。

fmap :: Functor f => (a -> b) -> f a -> f b

应用函子:(Applicative) 首先是个函子,额外提供如下俩操作

  1. 把普通值包裹为盒子值,比如普通的list作为应用函子时,pure a = [a]
     pure :: Applicative f => a => f a
    
  2. <*> (应用)是把盒子内的函数应用给另一个相同盒子内的值,比如 [\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 (想想为什么这么实现)

joinbind (>>=) 可以互相实现:

m >>= f = join (fmap f m)  

所以在别的语言中,才会有「实现了flatMap就是Monad了」这种说法,从以上的描述看起来,这是不够严谨的,忽略了Monad同时也得是Functor,以及也要具有Applicative的操作,并且需要符合函子定律,应用函子定律和单子定律。