整理一下 《Learn You a Haskell for Great Good !》 介绍的 Funtor
,Applicative Funtor
和 Monad
。
并不打算写 Monad
相关的教程 ╮(╯▽╰)╭
##柯里化
柯里化(Currying)是将多个参数的函数化成一系列单个参数函数组合的技术。
多参函数柯里化后传递和使用都更加灵活。
很多语言支持手动柯里化。这个过程很简单。比如在 JavaScript 中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
function (a,b){ return a b; }
// 对第一个参数柯里化 function OnePlus(b){ return 1 b; }
// 对第二个参数柯里化 function plusOne(a){ return a 1; }
|
在 Haskell 中多参函数接受参数不全时,会自动柯里化,返回一个接受剩余参数的函数。这个过程称为偏应用(Partial Apply,部分应用)
1 2 3 4 5 6
|
Prelude> ( 1) 2 3 -- ( 1) 是一个接受整形参数的函数,返回该参数 1 后的结果。 Prelude> (1 ) 2 3 -- (1 ) 是一个接受整形参数的函数,返回 1 该参数后的结果。
|
两个函数的类型是这样的
1 2 3 4
|
Prelude> :t ( 1) ( 1) :: Num a => a -> a Prelude> :t (1 ) (1 ) :: Num a => a -> a
|
类型签名
类型签名,或者说类型声明,用于声明函数的类型,如参数的类型,接受几个参数,返回类型等。
上面 ( 1)
函数的类型是
1 2
|
Prelude> :t ( 1) ( 1) :: Num a => a -> a
|
从左往右看,( 1)
说的是函数名。 ::
类型说明操作符。可读为 「……的类型是」
Num a
是一种类型约束。这部分很像变量声明,Num
指的是数字类型。 a
是变量名,可以任意取,习惯上为了方便偷懒使用单个字母。所以 Num a
的意思是 a
的类型为 Num
。
=>
表示推出。用于分隔类型约束和函数签名的主体。
a
表示接受一个变量 a
型的参数
->
表示返回
a
因为是在函数最后,所以就是返回一个 a
类型的参数。
Functor
Functor
是可以应用 fmap
的类型。
fmap
的类型是
1 2
|
Prelude> :t fmap fmap :: Functor f => (a -> b) -> f a -> f b
|
这里的签名有括号。不影响结果。可以简单的认为把 (a -> b)
视为接受 a
返回 b
的函数。
从签名中可以看出,fmap
接受一个函数 a -> b
,再接受一个 Funtor f
类型的参数 a ,返回一个 Funtor f
类型的 b
把签名改一下,改成fmap :: Functor f => (a -> b) -> (f a -> f b)
这样理解为接受一个函数返回另外一个参数和返回值都是 Funtor f
类型的函数
看具体的例子。比如 Maybe
是一个 Funtor
。
1 2 3
|
instance Functor Maybe where fmap f (Just x) = Just (f x) fmap f Nothing = Nothing
|
应用
1 2 3 4
|
Prelude> fmap ( 1) (Just 3) Just 4 Prelude> fmap ( 1) Nothing Nothing
|
并不是实现了 fmap
的实例都能称为 Funtor
。要想成为 Funtor
必须满足 Functor Law (函子律)。
1 2
|
fmap id = id fmap f . g = fmap f . fmap g
|
第一条中 id
是一个返回自身的函数。也就是 x -> x
。fmap id = id
实际上是 point-free 写法,也就是无参写法。
写得完整一点是 fmap id x = id x
。意思是 fmap
应用返回自身的函数相当于直接应用返回自身的函数。
1 2 3 4 5 6
|
Prelude> fmap id (Just 3) Just 3 -- fmap id (Just 3) = Just (id 3) = Just 3 Prelude> id (Just 3) Just 3 -- id (Just 3) = (x -> x) (Just 3) = Just 3
|
第二条说的是分配律。也就是应用两个函数的组合等用于分别应用两个函数结果的组合。
写的完整一点是 fmap f . g x = fmap f (fmap g x)
1 2 3 4
|
Prelude> fmap ( ( 1) . (*2) ) (Just 3) Just 7 Prelude> fmap ( 1) (fmap (*2) (Just 3)) Just 7
|
Applicative Functor
Applicative Functor
是可以应用 pure
和 apply (<*>
) 的 Funtor
1 2 3
|
class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b
|
pure
的类型是 a -> f a
,用于将类型 a
转化为 Funtor f
类型的函数。
<*>
的类型是 f (a -> b) -> f a -> f b
,用于取出 Funtor f
类型中函数 a -> b
,再接受一个 Funtor f
类型的参数 a ,返回一个 Funtor f
类型 b 。
Maybe
是一个 Applicative Funtor
1 2 3 4
|
instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just f) <*> something = fmap f something
|
应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
Prelude> pure Nothing Nothing Prelude> pure ( 1) <*> Just 3 Just 4 Prelude> Just ( 1) <*> Just 3 Just 4 Prelude> pure ( ) <*> Just 1 <*> Just 3 Just 4 -- 类似于柯里化后的函数的应用过程 -- pure ( ) <*> Just 1 <*> Just 3 -- Just ( ) <*> Just 1 <*> Just 3 -- Just ( 1) <*> Just 3 -- Just ( 1 3)< 大专栏 Haskell 中的 Functor Applicative Functor 和 Monad · 拖鞋党的拖鞋摊/span> -- Just 4
|
同样并不是实现了 pure
和 <*>
的类型就是 Applicative Funtor
。
要想成为 Applicative funtor
必须满足 Applicative Functor Law 。
1 2 3 4 5
|
pure f <*> x = fmap f x pure id <*> v = v pure (.) <*> u <*> v <*> w = u <*> (v <*> w) pure f <*> pure x = pure (f x) u <*> pure y = pure ($ y) <*> u
|
在第一条 pure f <*> x = fmap f x
可以得到其他几条
对于 Maybe
来说是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
Prelude> pure ( 1) <*> Just 3 Just 4 -- pure ( 1) <*> 3 = Just ( 1) <*> 3 = fmap ( 1) 3 Prelude> fmap ( 1) (Just 3) Just 4 Prelude> pure id <*> Just 3 Just 3 -- pure id <*> Just 3 = fmap id (Just 3) Prelude> fmap id (Just 3) Just 3 Prelude> ((pure (.) <*> Just ( 1)) <*> Just (*2)) <*> Just 3 Just 7 -- ((pure (.) <*> Just ( 1)) <*> Just (*2)) <*> Just 3 -- ((Just (.) <*> Just ( 1)) <*> Just (*2)) <*> Just 3 -- (Just ((.) ( 1)) <*> Just (*2)) <*> Just 3 -- (Just (( 1) . )) <*> Just (*2)) <*> Just 3 -- (Just (( 1 . ) (*2))) <*> Just 3 -- (Just (( 1) . (*2))) <*> Just 3 -- fmap (( 1) . (*2)) (Just 3) -- fmap ( 1) (fmap (*2) (Just 3)) -- fmap ( 1) (Just (*2) <*> (Just 3)) -- Just ( 1) <*> (Just (*2) <*> Just 3) Prelude> Just ( 1) <*> (Just (*2) <*> Just 3) Just 7 Prelude> pure ( 1) <*> pure 3 :: Maybe Int Just 4 -- pure ( 1) <*> pure 3 -- Just ( 1) <*> Just 3 -- Just (( 1) 3) -- pure (( 1) 3) Prelude> pure ( ( 1) 3) :: Maybe Int Just 4 Prelude> Just ( 1) <*> pure 3 Just 4 -- Just ( 1) <*> pure 3 -- Just ( 1) <*> Just 3 -- Just (( 1) (3)) -- Just (($ 3) ( 1)) -- Just ($ 3) <*> Just ( 1) -- pure ($ 3) <*> Just ( 1) Prelude> pure ($ 3) <*> Just ( 1) Just 4
|
Monad
Monad
是可以应用 bind (>>=
)的 Applicative Funtor
1 2 3
|
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b
|
这里的 return
相当于 Applicative Funtor
的 pure
。
不出所料的 Maybe
也是一个 Monad
1 2 3 4
|
instance Monad Maybe where return = Just Nothing >>= f = Nothing (Just x) >>= f = f x
|
应用
1 2 3 4 5 6 7 8
|
Prelude> return 1 :: Maybe Int Just 1 Prelude> return Nothing Nothing Prelude> Nothing >>= (x -> return (1 x)) Nothing Prelude> Just 3 >>= (x -> return (1 x)) Just 4
|
同样并不是实现了 >>=
就是 Monad
。要想成为 Monad
必须满足 Monad Law (单子律)
1 2 3
|
return x >>= f = f x m >>= return = m (m >>= f) >>= g = m >>= (x -> f x >>= g)
|
对于 Maybe
来说是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
Prelude> return 3 >>= (x -> return (x 1)) ::Maybe Int Just 4 -- return 3 >>= (x -> return (x 1)) -- Just 3 >>= (x -> return (x 1)) -- (x -> return (x 1)) 3 Prelude> (x -> return (x 1)) 3 ::Maybe Int Just 4 Prelude> Just 3 >>= return Just 3 -- Just 3 >>= return -- return 3 Prelude> Just 3 >>= (x -> return (x*2)) >>= (x -> return (x 1)) Just 7 -- Just 3 >>= (x -> return (x*2)) >>= (x -> return (x 1)) -- (x -> return (x*2)) 3 >>= (x -> return (x 1)) -- Just 6 >>= (x -> return (x 1)) -- (x ->return (x 1)) 6 -- Just 7 Prelude> Just 3 >>= (x -> return (x*2) >>= (x -> return (x 1))) Just 7 -- (x -> return (x*2) >>= (x -> return (x 1))) 3 -- return (3*2) >>= (x -> return (x 1)) -- Just 6 >>= (x -> return (x 1)) -- (x -> return (x 1)) 6 -- return (6 1) -- Just 7
|
最后
还有 Comonad
我懒得来写了(逃