[英]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
但Stream
和f
的組成不是MStream f
! 相反, Compose Stream fa
與Stream (fa)
同構。
我想知道MStream
是否是任何兩個應用程序的組合。
編輯:
我想提供一個類別理論觀點。 變換器是應用仿t
的C
類(即具有強度的松散幺正仿t
)的“好的”endofunctor,以及從C
到t
的標識的自然變換liftA
。 更普遍的問題是現在存在哪些有用的變換器不具有“與g
組合”的形式(其中g
是應用的)。 我的主張是MStream
就是其中之一。
好問題! 我相信這個問題有兩個不同的部分:
廣告1: Monad變壓器是組合monad的必要條件。 Monads 不直接撰寫 。 似乎需要monad變換器提供的額外信息,告訴每個monad如何與其他monad組合(但可能是這些信息已經以某種方式存在,請參閱是否有monad沒有相應的monad變壓器? )。
另一方面, applicatives直接組成 ,請參閱Data.Functor.Compose 。 這就是為什么不需要應用變壓器進行組合。 它們也在產品 (但不是副產品 )下關閉。
例如,具有無限流 data Stream a = Cons a (Stream a)
和另一個應用g
, Stream (ga)
和g (Stream a)
都是應用程序。
但即使Stream
也是一個monad( join
采用二維流的對角線),它與另一個monad m
組合將不會, Stream (ma)
和m (Stream a)
stream m (Stream a)
都不會是monad。
此外,正如我們所看到的,它們都與您的MStream g
(它非常接近ListT
完全正確 )不同,因此:
廣告2: 所有應用程序都可以從一組給定的原語構建嗎? 顯然不是。 一個問題是構造和數據類型:如果f
和g
是應用,則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.