应用变压器是否真的是多余的?

有很多关于Applicative不需要自己的变压器类的讨论,如下所示:

class AppTrans t where
    liftA :: Applicative f => f a -> t f a

但是我可以定义应用变形金刚似乎不是应用的组成! 例如副作用的流:

data MStream f a = MStream (f (a, MStream f a))

提升只是在每一步都会产生副作用:

instance AppTrans MStream where
    liftA action = MStream $ (,) <$> action <*> pure (liftA action)

如果f是应用程序,那么MStream f也是:

instance Functor f => Functor (MStream f) where
    fmap fun (MStream stream) = MStream $ ((a, as) -> (fun a, fmap fun as)) <$> stream

instance Applicative f => Applicative (MStream f) where
    pure = liftA . pure
    MStream fstream <*> MStream astream = MStream
        $ ((f, fs) (a, as) -> (f a, fs <*> as)) <$> fstream <*> astream

我知道,出于任何实际的目的, f应该是monad:

joinS :: Monad m => MStream m a -> m [a]
joinS (MStream stream) = do
    (a, as) <- stream
    aslist <- joinS as
    return $ a : aslist

但是,虽然MStream m有一个Monad实例,但它效率不高。 (或者甚至不正确?) Applicative实例实际上非常有用!

现在请注意,通常的流出现为身份仿函数的特例:

import Data.Functor.Identity
type Stream a = MStream Identity a

Streamf的组合不是MStream f ! 相反, Compose Stream faStream (fa)同构。

我想知道MStream是否是任何两个应用程序的组合。

编辑:

我想提供一个类别理论观点。 变压器是一个“好” endofunctor t的类别C应用性函子(带强度即不严monoidal函子)的,具有天然转化一起liftA上从身份Ct 。 更普遍的问题是,现在有什么有用的变换器存在非“与g组成”的形式(其中g是一个应用)。 我的说法是, MStream就是其中之一。


伟大的问题! 我相信这个问题有两个不同的部分:

  • 现有应用程序或monad组合成更复杂的应用程序。
  • 从一些给定的起始集构建所有应用程序/ monad。
  • 广告1: Monad变压器是结合单声道的关键。 Monad不直接撰写。 似乎需要由单子变换器提供额外的信息来说明每个单子如何与其他单子组合(但它可能是这种信息已经以某种方式存在,请参阅是否有一个monad没有相应的monad变压器?)。

    另一方面, 应用程序直接编写,请参阅Data.Functor.Compose。 这就是为什么不需要应用变压器的组成。 它们也在产品下关闭(但不是副产品)。

    例如,具有无限流data Stream a = Cons a (Stream a)和另一个应用gStream (ga)g (Stream a)都是可应用的。

    但即使Stream也是一个monad( join是一个二维流的对角线),但它与另一个monad m组合不会成立, Stream (ma)m (Stream a)都不会是monad。

    此外,正如我们所看到的,它们与您的MStream g (与ListT非常接近)完全不同,因此:

    广告2: 所有应用程序是否可以从一些特定的基元构建而成? 显然不是。 一个问题是构造和数据类型:如果fg是可应用的,则Either (fa) (ga)不会,因为我们不知道如何构成Right h <*> Left x

    另一个构建原语是采取固定点,就像在你的MStream例子中一样。 在这里,我们可能会试图通过定义类似的东西来概括构造

    newtype Fix1 f a = Fix1 { unFix1 :: f (Fix1 f) a }
    
    instance (Functor (f (Fix1 f))) => Functor (Fix1 f) where
        fmap f (Fix1 a) = Fix1 (fmap f a)
    
    instance (Applicative (f (Fix1 f))) => Applicative (Fix1 f) where
        pure k = Fix1 (pure k)
        (Fix1 f) <*> (Fix1 x) = Fix1 (f <*> x)
    

    (这需要不那么好的UndecidableInstances )然后

    data MStream' f g a = MStream (f (a, g a))
    
    type MStream f = Fix1 (MStream' f)
    
    链接地址: http://www.djcxy.com/p/66627.html

    上一篇: Are applicative transformers really superfluous?

    下一篇: Can I constrain a type family?