簡體   English   中英

應用變壓器真的是多余的嗎?

[英]Are applicative transformers really superfluous?

有很多談論的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是否是任何兩個應用程序的組合。

編輯:

我想提供一個類別理論觀點。 變換器是應用仿tC類(即具有強度的松散幺正仿t )的“好的”endofunctor,以及從Ct的標識的自然變換liftA 更普遍的問題是現在存在哪些有用的變換器不具有“與g組合”的形式(其中g是應用的)。 我的主張是MStream就是其中之一。

好問題! 我相信這個問題有兩個不同的部分:

  1. 現有的應用程序或monad組合成更復雜的應用程序或monad。
  2. 從一些給定的起始集構建所有 applicative / monad。

廣告1: Monad變壓器是組合monad的必要條件。 Monads 不直接撰寫 似乎需要monad變換器提供的額外信息,告訴每個monad如何與其他monad組合(但可能是這些信息已經以某種方式存在,請參閱是否有monad沒有相應的monad變壓器? )。

另一方面, applicatives直接組成 ,請參閱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) stream 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM