- What's the category of monads? What are the arrows in that category?
The category where the objects are monads, i.e., types T
of kind Type -> Type
with Monad
instances, and the arrows A -> B
are natural transformations between their underlying functors, conventionally represented in Haskell by functions of type forall x. A x -> B x
(although strictly speaking parametricity is a stronger condition than naturality).
There’s an implementation of this in the mmorph package.
The initial object in this category is Identity
, since for any monad T
there’s exactly one natural transformation forall x. Identity x -> T x
. Dually, I think the final object is Const ()
.
- Why are some monad transformers functors on the category of monads (
MaybeT
, RWST
, etc), but some not (ContT
, SelectT
)?
A functor in this category would need a lifted fmap
:
fmap'
:: forall m n. (Monad m, Monad n)
=> (forall x. m x -> n x) -> forall x. T m x -> T n x
And you can’t implement this in general for ContT
and SelectT
. I’m not sure precisely why, but it seems to depend on variance: we’re trying to implement a covariant functor, but ContT
and SelectT
are invariant in their underlying monads, e.g., m
occurs both positively and negatively in the (a -> m r) -> m r
inside a ContT r m a
.
- What good does it do, from a programming perspective, to be a functor on the category of monads? Why should I care as a consumer of the library?
If you have a general way to “run” a monad m
in a monad n
, you can’t necessarily lift that into ContT
or SelectT
; you’re stuck with the more restricted mapping operations like these:
mapSelectT :: (m a -> m a) -> SelectT r m a -> SelectT r m a
mapContT :: (m r -> m r) -> ContT r m a -> ContT r m a
Where the underlying monad and result type are fixed. So you can’t always freely hoist actions within a stack that uses these transformers.
IO String
into aMaybeT IO String
, but it's not possible to convert anIO String
into aSelectT <whatever type> IO String
– user253751Control.Monad.Morph
docs. – duplode