You can do this using hoist
from the mmorph
package. hoist
lets you modify the base monad of anything that implements MFunctor
(which is most monad transformers):
hoist :: (MFunctor t) => (forall x . m x -> n x) -> t m r -> t n r
You can then use it for your problem like this:
co' tma ma = hoist (co ma) tma
Then you're done!
To understand why that works, let's go through the types step by step:
co :: (Monad m) => m a -> m a -> m a
ma :: (Monad m) => m a
co ma :: (Monad m) => m a -> m a
hoist (co ma) :: (Monad m, MFunctor t) => t m a -> t m a
tma :: (Monad m, MFunctor t) => t m a
hoist (co ma) tma :: (Monad m, MFunctor t) => t m a
Note that hoist
has certain laws it must satisfy that ensure that it does "the right thing" that you would expect:
hoist id = id
hoist (f . g) = hoist f . hoist g
These are just functor laws, guaranteeing that hoist
behaves intuitively.
hoist
is provided in the Control.Monad.Morph
module of the mmorph
package, which you can find here. The bottom of the main module has a tutorial teaching how to use the package