Lets say I have a function
f :: State [Int] Int
and a function:
g :: StateT [Int] IO Int
I want to use f
in g
and pass the state between them. Is there a library function forStateT (return . runState f)
? Or in general, given a monad transformer with a corresponding monad, is there a library function for it?
In even more general, what you're trying to do is apply a transformation to an inner layer of a transformer stack. For two arbitrary monads, the type signature might look something like this:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
Basically a higher-level fmap
. In fact, it would probably make even more sense to combine it with a map over the final parameter as well:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
Clearly this isn't going to be possible in all cases, though when the "source" monad is Identity
it's likely to be easier, but I can imagine defining another type class for the places it does work. I don't think there's anything like this in the typical monad transformer libraries; however, some browsing on hackage turns up something very similar in the Monatron
package:
class MonadT t => FMonadT t where
tmap' :: FunctorD m -> FunctorD n -> (a -> b)
-> (forall x. m x -> n x) -> t m a -> t n b
tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b)
-> t m a -> t n a
tmap = tmap' functor functor id
In the signature for tmap'
, the FunctorD
types are basically ad-hoc implementations of fmap
instead of using Functor
instances directly.
Also, for two Functor-like type constructors F and G, a function with a type like (forall a. F a -> G a)
describes a natural transformation from F to G. There's quite possibly another implementation of the transformer map that you want somewhere in the category-extras
package but I'm not sure what the category-theoretic version of a monad transformer would be so I don't know what it might be called.
Since tmap
requires only a Functor
instance (which any Monad
must have) and a natural transformation, and any Monad
has a natural transformation from the Identity
monad provided by return
, the function you want can be written generically for any instance of FMonadT
as tmap (return . runIdentity)
--assuming the "basic" monad is defined as a synonym for the transformer applied to Identity
, at any rate, which is generally the case with transformer libraries.
Getting back to your specific example, note that Monatron does indeed have an instance of FMonadT
for StateT
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With