Add Applicative instances for MTL types
Bas van Dijk
v.dijk.bas at gmail.com
Wed Jan 14 12:16:42 EST 2009
Thanks for the reply.
On Wed, Jan 14, 2009 at 2:50 PM, Ross Paterson <ross at soi.city.ac.uk> wrote:
> The Functor instances could depend on Functor rather than Applicative.
Ok you mean like:
instance Functor m => Functor (ErrorT e m) where
fmap f = ErrorT . fmap (fmap f) . runErrorT
instance Functor m => Functor (ListT m) where
fmap f = ListT . fmap (fmap f) . runListT
instance (Functor m) => Functor (ReaderT r m) where
fmap f = ReaderT . fmap (fmap f) . runReaderT
instance (Functor m, Monoid w) => Functor (WriterT w m) where
fmap f = WriterT . fmap (\(x, w) -> (f x, w)) . runWriterT
I could update the patch with this or I can create a separate ticket
for it. What do you think?
The latter instance indicates that WriterT should have its inner tuple reversed:
newtype WriterT w m a = WriterT { runWriterT :: m (a, w) } -->
newtype WriterT w m a = WriterT { runWriterT :: m (w, a) }
Because then we can write the more consistent:
instance (Functor m, Monoid w) => Functor (WriterT w m) where
fmap f = WriterT . fmap (fmap f) . runWriterT
But this is probably a ticket on it own.
> Even though Applicative is not a superclass of Monad, I think we ought to
> ensure that the instances are compatible. That is, if an Applicative
> is also a Monad, then we should have pure = return and (<*>) = ap.
Yes, but what if an Applicative isn't a Monad?
We can't have two instances because they overlap:
instance Monad m => Applicative (ErrorT e m) where
pure = return
(<*>) = ap
instance Applicative m => Applicative (ErrorT e m) where
pure = ErrorT . pure . pure
ef <*> ex = ErrorT $ liftA2 (<*>) (runErrorT ef) (runErrorT ex)
I think the latter is more useful because there are more Applicatives
than Monads out there.
> This fails for your ErrorT instance: ap runs the second computation
> only if the first succeeded, while (<*>) runs them both before checking
> for errors. It needs a Monad constraint (like StateT), though not an
> Error constraint.
But isn't 'runErrorT ex' only evaluated when 'runErrorT ef' returns
'Right f' because of lazy evaluation?
>> * Can we get rid of the Monad and MonadPlus constraints in the
>> Applicative and Alternative instances for StateT and RWST?
>
> I don't think so: you need part of the value generated by the first
> computation, namely the state (inside the f), to construct the second one.
> You can do that in a Monad, but not in an Applicative.
Yes I thought so.
> At Henning Thielemann's request, I've recently put up on hackage a
> restructuring of the mtl into three packages, to provide three different
> interfaces to the same monad transformers:
>
> transformers: a Haskell 98 package with the MonadTrans class, concrete
> monad transformers, operations and liftings.
> monads-fd: multi-parameter monad classes using functional dependencies,
> with instances for these transformers. (Almost backward-compatible
> with the mtl package.)
> monads-tf: monad classes using type families, with instances for these
> transformers.
>
> The first one includes Applicative instances like these.
Yes I saw it. Very nice! What is the long term goal of these
libraries? Are they intended to replace mtl one day?
More information about the Libraries
mailing list