bheklilr 的回答让我想到了一个例子,在这个例子中,monad 转换器产生了一些不是 monad 的东西。一个不是 monad 的著名例子是ZipList
. 我们可以制作一个变体,在每个级别运行一个单子动作:
import Control.Applicative
import Control.Arrow ((***))
import Control.Monad
import Control.Monad.Trans
-- | A list where each step is produced by a monadic action.
data ListT m a = Nil | Cons (m (a, ListT m a))
这实际上是一个 monad 流。它可以很容易地制成aFunctor
和anApplicative
instance Monad m => Functor (ListT m) where
fmap f Nil = Nil
fmap f (Cons k) = Cons $ (f *** fmap f) `liftM` k
instance Monad m => Applicative (ListT m) where
pure x = Cons $ return (x, pure x)
Cons mf <*> Cons mx = Cons $ do
(f, fs) <- mf
(x, xs) <- mx
return (f x, fs <*> xs)
_ <*> _ = Nil
但显然不是单子。所以我们有一个MonadTrans
实例可以将 monad 转换为仅Applicative
.
instance MonadTrans ListT where
lift mx = Cons $ (\x -> (x, lift mx)) `liftM` mx
(整件事让我意识到,ZipSink
在额外的导管中进行实验也是一个很好的例子。)
然而,这又提出了另一个问题:如果我们想要这样的变形金刚,它们应该遵守什么法律?的法律MonadTrans
定义为
lift . return = return
lift (m >>= f) = lift m >>= (lift . f)
所以在我们的例子中,我们可能希望像
lift (f `liftM` x) = fmap f (lift x)
lift . return = pure
lift (m `ap` f) = lift m <*> lift f