
Thanks for the reply.
On Wed, Jan 14, 2009 at 2:50 PM, Ross Paterson
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?