【发布时间】:2016-10-12 04:18:26
【问题描述】:
有很多关于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 f a 与 Stream (f a) 同构。
我想知道MStream 是否是任意两个应用程序的组合。
编辑:
我想提供一个范畴论的观点。 Transformer 是应用函子类别C 上的“不错”内函子t(即具有强度的松散单曲面函子),以及从C 上的身份到t 的自然转换liftA。现在更普遍的问题是存在哪些有用的转换器不是“与g 组合”形式(其中g 是一个应用程序)。我的主张是MStream 就是其中之一。
【问题讨论】: