函子 应用函子 单子

函子 应用函子 单子

定义

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
posted @ 2025-05-08 16:25  (.)$(.)  阅读(10)  评论(0)    收藏  举报