Where are the Applicative
transformer classes? I wanted to use transformer classes for the applicative transformer stack in a previous answer, but they don't seem to exist.
The transformers package and many others are full of transformers that preserver Applicative
structure, even when the underlying structure isn't a Monad
.
A quick glance at transformers
has Applicative
instances for most of the transformers.
Applicative f => Applicative (Backwards f)
Applicative f => Applicative (Lift f)
Applicative (ContT r m)
Applicative m => Applicative (IdentityT m)
Applicative m => Applicative (ReaderT r m)
(Monoid w, Applicative m) => Applicative (WriterT w m)
(Applicative f, Applicative g) => Applicative (Compose f g)
(Applicative f, Applicative g) => Applicative (Product f g)
Only transformers for state and alternation (ExceptT
and MaybeT
) require an underlying monad for the Applicative
instance.
(Functor m, Monad m) => Applicative (ExceptT e m)
(Functor m, Monad m) => Applicative (MaybeT m)
(Monoid w, Functor m, Monad m) => Applicative (RWST r w s m)
(Functor m, Monad m) => Applicative (StateT s m)
There's a class for Monad
transformers. I can see how something could require this Monad
constraint, since it can't be introduced elsewhere.
class MonadTrans t where
lift :: (Monad m) => m a -> t m a
Where's the class for Applicative
transformers?
class ApTrans t where
liftAp :: (Applicative f) => f a -> t f a
Or just plain old transformers (though I can't imagine any laws for this)?
class Trans t where
liftAny :: f a -> t f a
Due to the difference only in polymorphic constraints, these typeclasses have a strange variance pattern. Except for their laws, which have to consider unexpressible constraints, anything that is an instance of Trans
should automatically be an instance of ApTrans
and MonadTrans
, and anything that's an instance of ApTrans
should automatically be an instance of MonadTrans
.
If we move on to the mtl library, the classes there are also incompatible with an Applicative
transformer stack. All of the mtl classes I'm familiar with have a Monad
constraint. For example, here's MonadReader
class Monad m => MonadReader r m | m -> r where
-- | Retrieves the monad environment.
ask :: m r
ask = reader id
-- | Executes a computation in a modified environment.
local :: (r -> r) -- ^ The function to modify the environment.
-> m a -- ^ @Reader@ to run in the modified environment.
-> m a
-- | Retrieves a function of the current environment.
reader :: (r -> a) -- ^ The selector function to apply to the environment.
-> m a
reader f = do
r <- ask
return (f r)
What is the purpose of the Monad
constraint? It makes MonadReader
and the MonadReader
instances for many of the above transformers incompatible with Applicative
transformer stacks.
I would naively write something like
class Reader r m | m -> r where
ask :: m r
local :: (r -> r) -> m a -> m a
or even split local
into a separate class.
class Reader r m | m -> r where
ask :: m r
class (Reader r m) => Local r m | m -> r where
local :: (r -> r) -> m a -> m a
local
might be quite hard to use without a Monad
instance. A more useful interface without the Monad
constraint would be something like
class (Reader r m) => Local r m | m -> r where
local :: m (r -> r) -> m a -> m a
Are there existing transformer classes somewhere that don't have the Monad
constraint, or is there an actual need for yet another transformer class library?