1.Functor, Applicative, 和Monad, 都是deal with有context的值的类型(typeclass), 就像一个包裹着礼物的盒子.
比较经典是三个例子是Maybe, List, 和Function, 他们既是Functor, 也是Applicative,也是Monad:
Maybe 的context代表值是否存在
[], 也就是List 的context代表非确定性
(->) r, 也就是接受返回值类型的类型构造器,他的context是传入值。
2. 他们有不同的方法
class Functor f where
fmap::(a->b) -> f a -> f b
这里的f不是具体类型,而是一个取一个类型参数的类型构造器
比如Maybe Int是一个具体类型,而Mabybe是一个取一个类型参数的类型构造器。
类似的,[]对应[Int], (->) r 对应 (->) r a.
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
可以看到Applicative和Functor关联性很大。第一行开始Applicative类的定义,同时引入了一个约束类。这个类约束说:如果我们想把某个类型构造器变成Applicative类型类的实例,它必然先成为Functor的实例。
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
最经典的几个例子都是: Maybe, List, Function
List:
Functor
instance Functor [] where
fmap = map
Applicative
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fx, x <- xs]
example:
ghci>[(*0),(+100),(^2)]<*>[1,2,3]
[0,0,0,101,102,103,1,4,9]
Left-associative:
ghci>[(+),(*)]<*>[1,2]<*>[3,4]
[4,5,5,6,3,4,6,8]
Monad
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
example:
ghci>[3,4,5]>>=\x->[x,-x]
[3,-3,4,-4,5,-5]
Function:
Functor:
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
根据fmap的类型:
fmap :: (a -> b) -> f a -> f b
把f替换成(->) r:
( a -> b ) -> ( (->) r a ) -> ( (->) r b )
写成中缀形式:
( a -> b ) -> ( r -> a ) -> ( r -> b )
那么很明显, 把函数( r -> a )和( a- > b)组合起来,就得到函数( r-> b)
所以说定义这个实例的另外一种方法是:
instance Functor ( (->) r) where
fmap = (.)
Applicative:
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
(<*>) :: f (a -> b) -> f a -> f b
funny thing here: f (a -> b) 把 (->) r带入f, 意思是传入类型为r的参数,返回(a->b)类型的函数,那么容易理解 :
f <*> g = \x -> f x (g x)
例子
ghci>:t (+)<$>(+3)<*>(*100)
(+)<$>(+3)<*>(*100)::(Numa)=>a->a
ghci>(+)<$>(+3)<*>(*100)$5
508
ghci>(\x y z->[x,y,z])<$>(+3)<*>(*2)<*>(/2)$5
[8.0,10.0,2.5]
Monad:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
Monad最经典的用法是链式:
foo :: Maybe String
foo = Just 3 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y)))
结果 Just "3!"
分行写:
foo = Just 3 >>= (\x ->
Just "!" >>= (\y ->
Just (show x ++ y)))
用do记法:
foo = do
x <- Just 3
y <- Just "!"
Just (show x ++ y)