函子 应用函子 单子
函子 应用函子 单子
定义
Functor
class Functor f where
fmap :: (a -> b) -> f a -> f b
fmap id == id -- 恒等律
fmap (f . g) == fmap f . fmap g -- 组合律
Applicative
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
pure id <*> v = v -- 恒等律
pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- 组合律
pure f <*> pure x = pure (f x) -- 同态律
u <*> pure y = pure ($ y) <*> u -- 交换律
Monad
class Applicative m => Monad m where
return :: a -> m a
return = pure
(>>=) :: m a -> (a -> m b) -> m b
return a >>= k = k a -- 左恒等律
m >>= return = m -- 右恒等律
m >>= (\x -> k x >>= h) = (m >>= k) >>= h -- 结合律
do 语法糖
do
x1 <- m1 ⇒ m1 >>= \x1 -> ...
x2 <- m2 ⇒ m2 >>= \x2 -> ...
...
xn <- mn ⇒ mn >>= \xn -> ...
result ⇒ result
<=<
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = \x -> g x >>= f
k <=< return = k -- 左恒等律
return <=< m = m -- 右恒等律
f <=< (g <=< h) = (f <=< g) <=< h -- 结合律
Context 编程
类型构造子
context: 类型构造子为纯值附加计算上下文
类型构造子 | context | 组合语义 | pure value |
---|---|---|---|
基础 | |||
Maybe | 可能失败计算 | 短路: 任一失败则整体失败 | 成功值 |
Either | 带错误信息计算 | 短路: 保留第一个错误信息 | 成功值 |
[] | 非确定性计算 | 笛卡尔积: 所有可能组合 | 所有值 |
IO | 副作用计算 | 顺序执行: 保持副作用顺序 | IO 操作后值 |
(-> r) | 依赖环境计算 | 环境共享: 所有计算依赖同一环境 | 函数作用后值 |
状态 | |||
State | 状态计算 | 状态串联: 前输出状态为后输入状态 | 状态相关值 |
Reader | 只读环境计算 | 环境共享: 所有计算依赖同一环境 | 函数作用后值 |
Writer | 日志计算 | 日志积累: 幺半群合并日志 | 日志相关值 |
控制流 | |||
Cont | 延续传递计算 | 延续嵌套:前计算续延为后计算输入 | 延续值 |
ST | 安全状态计算 | 状态线程化: 状态修改在类型级别隔离 | 不产生副作用的值 |
Parser | 输入流解析计算 | 顺序消费: 逐步消耗输入值 | 解析结果值 |
并发 | |||
Par | 并行计算 | 并行执行: 独立计算并行运行, 依赖计算等前置完成 | 立即可用值 |
Async/Future | 异步计算 | 异步链接: 前一异步完成后触发下一个 | 立即解析的异步值 |
资源管理 | |||
Resource | 资源计算 | 资源生命周期: 确保资源被释放 | 不需要资源的值 |
STM | 软件事务内存 | 事务组合: 操作在同一事务中原子执行 | 事务执行结果 |
类型类
抽像 context 值的操作模式
类型类 | 模式 | 特性 | 操作 | 作用 |
---|---|---|---|---|
函数应用 | 函数 + 纯值 | 函数应用于纯值 | $ |
基础计算 |
Functor | 函数 + context 值 | 函数应用于 context 值 | fmap |
维护 context |
Applicative | context 函数 + context 值 | context 函数应用于 context 值 | <*> |
组合 context |
Monad | context 值 + a -> m b 函数 | context 值传递给 context 函数 | >>= |
传递 context |
Functor 由来
推广函数作用对象
函数穿透 context 作用于内部值
\(\rightarrow\) fmap
class Functor f where
fmap :: (a -> b) -> f a -> f b
fmap id == id -- 恒等律
fmap (f . g) == fmap f . gmap g -- 组合率
map
模式: 具体函数应用于列表类型
_ :: [a] -> [b]
_ [] = []
_ (x:xs) = f x : _ xs
抽像应用的具体函数为 f 得到 map
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
fmap
模式: map 应用函数到列表类型
map :: (a -> b) -> [a] -> [b]
抽像列表类型到参数化类型得到 fmap
fmap :: (a -> b) -> f a -> f b
Functor
参数化类型 f 归类为类型类 Functor
分类依据: fmap 和 laws
class Functor f where
fmap :: (a -> b) -> f a -> f b
context
参数化类型会给纯值附加 context
函数应用于纯值
_ :: (a -> b) -> a -> b
fmap 是对函数应用的升华
fmap 维护 context 结构不变
fmap :: (a -> b) -> f a -> f b
laws
函数应用 laws
id x == x -- 恒等律
(f . g) x == f (g x) -- 组合律
升华函数应用 laws 得到 functor laws
fmap id == id -- 恒等律
fmap (f . g) == fmap f . gmap g -- 组合率
Applicative 由来
推广函数参数数量
并行组合 context 值
fmap \(\rightarrow\) <*>
参数数量
希望做到任意参数函数应用于 context 值
fmap0 :: a -> f a
fmap1 :: (a -> b) -> f a -> f b
fmap2 :: (a -> b -> c) -> f a -> f b -> f c
fmap3 :: (a -> b -> c -> d) -> f a -> f b -> f c -> f d
...
柯里化
尽管 (a -> b) -> f a -> f b 包含 (a -> b -> c) -> f a -> f (b -> c)
能解决参数数量的问题, 但存在柯里化问题: 无法挨个输入参数
(a -> b -> c) -> f a -> f b -> ?
-- fmap
= f (b -> c) -> f b -> ? -- fmap 无法做到
= f (b -> c) -> f b -> f c -- 抽象出 <*>
由于 (a -> b -> c) 函数在 fmap 的作用下输入参数 f a 输出 f (b -> c)
如果能做到 f (b -> c) 输入参数 f b 输出 f c 就能做到任意参数函数作用于 context 值
即 context 函数作用于 context 值
<*>
抽像参数数量和柯里化得到 <*>
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
纯函数柯里化
g x
g x y
g x y z
context 函数柯里化
fmap0 = pure
fmap1 g x = pure g <*> x
fmap2 g x y = pure g <*> x <*> y
fmap3 g x y z = pure g <*> x <*> y <*> z
...
Applicative
定义了 <*> 的 functor 类型归类为类型类 Applicative
分类依据: <*> 和 laws
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
context
将 Applicative 视为带 context 编程,
Applicative 组合 context
context 具体定义由底层 Functor 确定
(<*>) :: f (a -> b) -> f a -> f b
laws
函数应用 laws
id x == x -- 恒等律
(f . g) x == f (g x) -- 组合律
f y = ($ y) f -- 交换律
升华函数应用 laws 得到 applicative laws
pure id <*> v = v -- 恒等律
pure (.) <*> u <*> v <*> w = u <*> (v <*> w) -- 结合律
pure f <*> pure x = pure (f x) -- 同态律
u <*> pure y = pure ($ y) <*> u -- 交换律
Monad 由来
依赖性 context 计算
串行传递 context 值
<*> \(\rightarrow\) >>=
静态结构
Applicative 组合结构静态确定
g <*> x <*> y
无法根据前一步结果实时动态确定当前结果
g <*> x <*> y
= case g <*> x of
_ ->
_ ->
case g <*> x <*> y of
_ ->
_ ->
嵌套结构
Functor 应用输出 context 值函数会造成 context 嵌套
现实需求: 输出 context 值函数
fmap :: (a -> f a) -> f a -> f (f a)
拍平嵌套
join :: Monad m => m (m a) -> m a
join x = x >>= id
>>=
根据需求, 结合 fmap 和 join 得到 bind
mx >>= f = join (fmap f mx)
functor 的 fmap 和 applicative 的 <*> 中的函数和 context 函数都不具备生成 context 的能力, 仅仅是维护和组合 context 的能力
>>=
强大的关键在于 a -> m b
具有生成 context 的能力
从而做到动态确定 context 和依赖计算
mx >>= f >>= g >>= h
语法糖演进
do 语法糖
do
x <- mx -- 输入 mx, 抽离纯值
y <- my -- 生成 my, 抽离纯值
z <- mz -- 生成 mz, 抽离纯值
...
return res -- 生成结果 m res
safeDivide :: Int -> Int -> Maybe Int
-- 原始
f :: Maybe Int -> Maybe Int -> Maybe Int
f mx my = case mx of
Nothing -> Nothing
Just x -> case my of
Nothing -> Nothing
Just y -> safeDivide x y
-- bind
f mx my = mx >>= \x -> my >>= \y -> safeDivide x y
-- do
f mx my = do
x <- mx
y <- my
safeDivide x y
Monad
定义了 >>= 的 applicative 类型归类为类型类 Monad
分类依据: >>= 和 laws
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
context
将 Monad 视为带 context 编程,
Monad 传递 context
context 具体定义由底层 Functor 确定
(>>=) :: m a -> (a -> m b) -> m b
laws
函数应用 laws
id x == x -- 恒等律
(f . g) x == f (g x) -- 结合律
升华函数应用 laws 得到 monad laws
return a >>= k = k a -- 左恒等律
m >>= return = m -- 右恒等律
m >>= (\x -> k x >>= h) = (m >>= k) >>= h -- 结合律
重要函数
join
>>=
的 join 定义
mx >>= f = join (fmap f mx)
join :: (Monad m) => m (m a) -> m a
join mmx = do mx <- mmx
x <- mx
return x
mapM
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f [] = return []
mapM f (x:xs) = do
y <- f x
ys <- mapM f xs
return (y:ys)
filterM
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM p [] = return []
filterM p (x:xs) = do
b <- p x
ys <- filterM p xs
return (if b then x:ys else ys)
liftM
monad 版 fmap
liftM :: (Monad m) => (a -> b) -> m a -> m b
liftM f mx = mx >>= (\x -> return (f x))
liftM f mx = do
x <- mx
return (f x)
liftM2
monad 版 liftM2
liftM2 :: (Monad m) => (a -> b -> c) -> m a -> m b -> m c
liftM2 f mx my = do
x <- mx
y <- my
return (f x y)
ap
monad 版 <*>
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf mx = mf >>= \f -> mx >>= \x -> return (f x)
ap mf mx = do
f <- mf
x <- mx
return (f x)
sequenceA
sequenceA :: Applicative f => t (f a) -> f (t a)
sequenceA = traverse id
Instance
Maybe
context: 可能失败计算
组合语义: 短路, 任一失败则整体失败
pure value: 成功值
instance Functor Maybe where
fmap :: (a -> b) -> Maybe a -> Maybe b
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)
instance Applicative Maybe where
pure = Just
(<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
Nothing <*> _ = Nothing
Just f <*> x = fmap f x
instance Monad Maybe where
>>= :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing
(Just x) >>= f = f x
Either
context: 带失败信息计算
组合: 短路, 任一失败则整体失败
pure value: 成功值
instance Functor (Either e) where
fmap :: (a -> b) -> Either e a -> Either e b
fmap _ (Left x) = Left x
fmap f (Right y) = Right (f y)
instance Applicative (Either e) where
pure = Right
<*> :: Either e (a -> b) -> Either e a -> Either e b
Left e <*> _ = Left e
Right f <*> x = fmap f x
instance Monad (Either e) where
>>= :: Either e a -> (a -> Either e b) -> Either e b
Left x >>= _ = Left x
Right y >>= f = f y
[]
context: 非确定性计算
组合语义: 笛卡尔积, 所有可能组合
pure value: 所有值
instance Functor [] where
fmap :: (a -> b) -> [a] -> [b]
fmap = map
instance Applicative [] where
pure x = [x]
<*> :: [a -> b] -> [a] -> [b]
fs <*> xs = [f x | f <- fs, x <- xs]
instance Monad [] where
return x = [x]
>>= :: [a] -> (a -> [b]) -> [b]
xs >>= f = [y | x <- xs, y <- f x]
xs >>= f = concatMap f xs
IO
世界状态为输入输出
type IO a = World -> (a,World)
context: 副作用计算
组合语义: 顺序执行
pure value: IO 操作后值
instance Functor IO where
fmap :: (a -> b) -> IO a -> IO b
fmap f x = x >>= (pure . f)
instance Applicative IO where
pure = return
<*> :: IO (a -> b) -> IO a -> IO b
a <*> b = do
f <- a
x <- b
return (f x)
instance Monad IO where
>>= :: IO a -> (a -> IO b) -> IO b
a >>= f = do
x <- a
f x
((->) r)
context: 依赖环境计算
组合语义: 共享环境 r
pure value: 函数返回值
instance Functor ((->) r) where
fmap :: (a -> b) -> (r -> a) -> (r -> b)
fmap = (.)
instance Applicative ((->) r) where
pure = const
<*> :: (r -> a -> b) -> (r -> a) -> (r -> b)
f <*> g = \x -> f x (g x)
instance Monad ((->) r) where
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
g >>= f = \x -> f (g x) x