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))
也是适用的(您可以用通用的方式编写这样的实例)

另一方面,如果您有monad
M1
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