Haskell 应用程序组合,单子不';T
应用程序编写,单子不编写Haskell 应用程序组合,单子不';T,haskell,functional-programming,monads,monad-transformers,applicative,Haskell,Functional Programming,Monads,Monad Transformers,Applicative,应用程序编写,单子不编写 上述说法是什么意思?什么时候一个比另一个更可取?如果您有应用程序A1和A2,那么类型数据a3a=A3(A1(a2a))也是适用的(您可以用通用的方式编写这样的实例) 另一方面,如果您有monadM1和M2,那么类型data M3 a=M3(M1(M2 a))不一定是monad(对于组合而言,>=或join没有合理的通用实现) 一个例子是类型[Int->a](这里我们用(>)Int组成一个类型构造函数[],两者都是单子)。你写起来很容易 app :: [Int ->
上述说法是什么意思?什么时候一个比另一个更可取?如果您有应用程序
A1
和A2
,那么类型数据a3a=A3(A1(a2a))
也是适用的(您可以用通用的方式编写这样的实例)
另一方面,如果您有monadM1
和M2
,那么类型data M3 a=M3(M1(M2 a))
不一定是monad(对于组合而言,>=
或join
没有合理的通用实现)
一个例子是类型[Int->a]
(这里我们用(>)Int
组成一个类型构造函数[]
,两者都是单子)。你写起来很容易
app :: [Int -> (a -> b)] -> [Int -> a] -> [Int -> b]
app f x = (<*>) <$> f <*> x
但没有合理的定义
join :: [Int -> [Int -> a]] -> [Int -> a]
如果你不相信这一点,请考虑这个表达式:
join [\x -> replicate x (const ())]
在提供整数之前,必须将返回列表的长度设置为stone,但其正确长度取决于所提供的整数。因此,此类型不存在正确的join
函数
不幸的是,我们真正的目标,单子的合成,是更多的
困难的。。事实上,我们
实际上可以证明,在某种意义上,没有办法
仅使用
两个单子的操作(参见附录了解操作概要
证明)。因此,我们可能希望形成一个
组合是指如果有一些额外的结构连接
两部分
组成单子,如果我们比较类型
(<*>) :: Applicative a => a (s -> t) -> a s -> a t
(>>=) :: Monad m => m s -> (s -> m t) -> m t
它使用某种影响的结果来决定两种计算(例如发射导弹和签署停战协定),而
我们走了这么远,但现在我们的图层都乱七八糟了。我们有一个n(m(nt))
,所以我们需要去掉外部n
。正如Alexandre C所说,如果我们有合适的
swap :: n (m t) -> m (n t)
将n
向内排列,并将连接到另一个n
较弱的“双重适用”更容易定义
(<<**>>) :: (Applicative a, Applicative b) => a (b (s -> t)) -> a (b s) -> a (b t)
abf <<**>> abs = pure (<*>) <*> abf <*> abs
()::(应用程序a,应用程序b)=>a(b(s->t))->a(bs)->a(bt)
abf abs=纯()abf abs
因为层之间没有干涉
相应地,当您真正需要Monad
s的额外功能时,以及当您可以摆脱Applicative
支持的刚性计算结构时,认识到这一点是很好的
顺便说一句,请注意,尽管编写单子很困难,但它可能超出了您的需要。类型m(nv)
表示使用m
-effects进行计算,然后使用n
-effects对v
-value进行计算,其中m
-effects在n
-effects开始之前完成(因此需要交换
)。如果你只是想把m
-效果和n
-效果交织在一起,那么构图的要求可能太高了
应用程序编写,单子不编写
单子确实构成,但结果可能不是单子。
相反,两个应用程序的组合必然是一个应用程序。
我怀疑原始陈述的意图是“应用性构成,而单性不构成。”换言之,“Applicative
在composition下是封闭的,而Monad
不是。”分配律解
l:MN->NM就足够了
保证纳米的单体性。要看到这一点,你需要一个单位和一辆骡子。我将关注mult(该单元是unit\N unitM)
这并不保证MN是单子
然而,当你有分布律解时,关键的观察就开始起作用了
l1 : ML -> LM
l2 : NL -> LN
l3 : NM -> MN
因此,LM、LN和MN是单子。问题在于LMN是否是单子(通过
(MN)L->L(MN)
或者
N(LM)->(LM)N
我们有足够的结构来制作这些地图。然而,作为一个例子,我们需要一个六边形条件(这相当于杨-巴克斯特方程的表示)为了保证任一结构的一元性。事实上,在六边形条件下,两个不同的单子是重合的。这里有一些代码通过分配律来生成单子组合。注意,从任何单子到单子都有分配律可能,任一,编写器和[]
。另一方面,在读取器
和状态
中找不到这样的(一般)分布规律。对于这些,您将需要monad转换器
{-# LANGUAGE FlexibleInstances #-}
module ComposeMonads where
import Control.Monad
import Control.Monad.Writer.Lazy
newtype Compose m1 m2 a = Compose { run :: m1 (m2 a) }
instance (Functor f1, Functor f2) => Functor (Compose f1 f2) where
fmap f = Compose . fmap (fmap f) . run
class (Monad m1, Monad m2) => DistributiveLaw m1 m2 where
dist :: m2 (m1 a) -> m1 (m2 a)
instance (Monad m1,Monad m2, DistributiveLaw m1 m2)
=> Applicative (Compose m1 m2) where
pure = return
(<*>) = ap
instance (Monad m1, Monad m2, DistributiveLaw m1 m2)
=> Monad (Compose m1 m2) where
return = Compose . return . return
Compose m1m2a >>= g =
Compose $ do m2a <- m1m2a -- in monad m1
m2m2b <- dist $ do a <- m2a -- in monad m2
let Compose m1m2b = g a
return m1m2b
-- do ... :: m2 (m1 (m2 b))
-- dist ... :: m1 (m2 (m2 b))
return $ join m2m2b -- in monad m2
instance Monad m => DistributiveLaw m Maybe where
dist Nothing = return Nothing
dist (Just m) = fmap Just m
instance Monad m => DistributiveLaw m (Either s) where
dist (Left s) = return $ Left s
dist (Right m) = fmap Right m
instance Monad m => DistributiveLaw m [] where
dist = sequence
instance (Monad m, Monoid w) => DistributiveLaw m (Writer w) where
dist m = let (m1,w) = runWriter m
in do a <- m1
return $ writer (a,w)
liftOuter :: (Monad m1, Monad m2, DistributiveLaw m1 m2) =>
m1 a -> Compose m1 m2 a
liftOuter = Compose . fmap return
liftInner :: (Monad m1, Monad m2, DistributiveLaw m1 m2) =>
m2 a -> Compose m1 m2 a
liftInner = Compose . return
{-#语言灵活实例}
模块组件在哪里
进口管制
导入控件.Monad.Writer.Lazy
newtype Compose m1 m2 a=Compose{run::m1(m2 a)}
实例(函子f1,函子f2)=>函子(组合f1 f2),其中
fmap f=Compose.fmap(fmap f).run
类别(单子m1,单子m2)=>DistributiveLaw m1 m2,其中
地区::m2(m1 a)->m1(m2 a)
实例(Monad m1、Monad m2、DistributiveLaw m1 m2)
=>适用(组合m1 m2),其中
纯=返回
()=ap
实例(Monad m1、Monad m2、DistributiveLaw m1 m2)
=>单子(组成m1-m2),其中
return=Compose.return.return
组合m1m2a>>=g=
撰写$do m2a DistributiveLaw m[]其中
dist=序列
实例(Monad m,Monoid w)=>DistributiveLaw m(Writer w),其中
距离m=let(m1,w)=runm
做一个
m1 a->组合m1 m2 a
liftOuter=Compose.fmap返回
liftInner::(单子m1,单子m2,分配m1 m2)=>
m2 a->组合m1 m2 a
liftInner=Compose.return
任何两个应用函子都可以组合并生成另一个应用函子。但这不适用于单子。两个单子的组合并不总是单子。例如,状态
和列表
单子的组合(
swap :: n (m t) -> m (n t)
(<<**>>) :: (Applicative a, Applicative b) => a (b (s -> t)) -> a (b s) -> a (b t)
abf <<**>> abs = pure (<*>) <*> abf <*> abs
NMNM - l -> NNMM - mult_N mult_M -> NM
l1 : ML -> LM
l2 : NL -> LN
l3 : NM -> MN
{-# LANGUAGE FlexibleInstances #-}
module ComposeMonads where
import Control.Monad
import Control.Monad.Writer.Lazy
newtype Compose m1 m2 a = Compose { run :: m1 (m2 a) }
instance (Functor f1, Functor f2) => Functor (Compose f1 f2) where
fmap f = Compose . fmap (fmap f) . run
class (Monad m1, Monad m2) => DistributiveLaw m1 m2 where
dist :: m2 (m1 a) -> m1 (m2 a)
instance (Monad m1,Monad m2, DistributiveLaw m1 m2)
=> Applicative (Compose m1 m2) where
pure = return
(<*>) = ap
instance (Monad m1, Monad m2, DistributiveLaw m1 m2)
=> Monad (Compose m1 m2) where
return = Compose . return . return
Compose m1m2a >>= g =
Compose $ do m2a <- m1m2a -- in monad m1
m2m2b <- dist $ do a <- m2a -- in monad m2
let Compose m1m2b = g a
return m1m2b
-- do ... :: m2 (m1 (m2 b))
-- dist ... :: m1 (m2 (m2 b))
return $ join m2m2b -- in monad m2
instance Monad m => DistributiveLaw m Maybe where
dist Nothing = return Nothing
dist (Just m) = fmap Just m
instance Monad m => DistributiveLaw m (Either s) where
dist (Left s) = return $ Left s
dist (Right m) = fmap Right m
instance Monad m => DistributiveLaw m [] where
dist = sequence
instance (Monad m, Monoid w) => DistributiveLaw m (Writer w) where
dist m = let (m1,w) = runWriter m
in do a <- m1
return $ writer (a,w)
liftOuter :: (Monad m1, Monad m2, DistributiveLaw m1 m2) =>
m1 a -> Compose m1 m2 a
liftOuter = Compose . fmap return
liftInner :: (Monad m1, Monad m2, DistributiveLaw m1 m2) =>
m2 a -> Compose m1 m2 a
liftInner = Compose . return