11 函子以及Applicative
函子
函子是那些可以被map的类型,比如List, Maybe, Tree等。它们共有一个函数
1 | fmap :: (a -> b) -> f a -> f b |
IO 函子
1 | instance Functor IO where |
看看上面fmap的定义是不是很清晰,IO可以最为函子来看。
(->) 也是函子
a -> b 就相当于 (->) a b, -> 是一个中缀类型构造器(卧槽这都行)。
然后我们推算一下它的fmap:
1 | fmap :: (a -> b) -> f a -> f b |
所以fmap 对 函数而言就是函数编组(Function Composition)
函数提升(lifting)
1 | fmap :: (a -> b) -> (f a -> f b) |
就是一个函数的入参和出参都被函子包了一层,也是fmap的另一种理解。
函子俩定律
1
fmap id theFactor = theFactor
1
fmap (f . g) = fmap f . fmap g
Applicative
我们想把函子包的函数(如Just (*3))应用到函子包的值里,要咋办? Applicative就干这个
1 | class (Functor f) => Applicative f where |
pure 把任一一个值用包成函子
<*>把函子包着的函数应用出去
为了方便,fmap 还有个中缀的版本fmap = (<$>),然后就可以骚了:
1 | ghci> (++) <$> Just "johntra" <*> Just "volta" |
List 作为 Applicative
1 | instance Applicative [] where |
list的<*>运算结果是笛卡儿积
1 | ghci> [(+),(*)] <*> [1,2] <*> [3,4] |
IO 作为 Applicative
1 | instance Applicative IO where |
没毛病,函数也可以从IO传过来
函数作为Applicative
1 | instance Applicative ((->) r) where |
<*>比较难想出来,可以看下它的参数类型推导:
1 | <*> :: f (a -> b) -> f a -> f b |
1 | Prelude> (\x y z -> sum [x, y, z]) <$> (+3) <*> (*3) <*> (/3) $ 99 |
挺难理解的,作为课后题。
ZipList
因为list <*> list 是笛卡儿积,我想一对一map怎么办? Haskell 在Control.Applicative里已经定义好了
1 | instance Applicative ZipList where |
Applicative 定律
1 | pure id <*> v = v |
LiftA2
定义在Control.Applicative里
1 | liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c |
Applicative 比 普通Functor强在它可以lifting需要N个参数的函数
用它造个轮子:将[f a] 转成 f [a],f 是任意Applicative
1 | sequenceA :: (Applicative f) => [f a] -> f [a] |