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 for
StateT (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:
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: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 theMonatron
package:In the signature for
tmap'
, theFunctorD
types are basically ad-hoc implementations offmap
instead of usingFunctor
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 thecategory-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 aFunctor
instance (which anyMonad
must have) and a natural transformation, and anyMonad
has a natural transformation from theIdentity
monad provided byreturn
, the function you want can be written generically for any instance ofFMonadT
astmap (return . runIdentity)
--assuming the "basic" monad is defined as a synonym for the transformer applied toIdentity
, 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
forStateT
.Such a function is not definable for all monad transformers. The
Cont r
monad, for example, can't be lifted intoContT r IO
because that would require turning a continuation in the IO monad (a -> IO r
) into a pure continuation (a -> r
).What you are asking for is a mapping (known as a monad morphism) from a monad
StateT m
toStateT n
. I'll be using the themmorph
library, which provides a very nice set of tools for working with monad morphisms.To perform the
State -> StateT m
transform you are looking for, we'll start by defining a morphism to generalize theIdentity
monad embedded inState
,Next we'll want to lift this morphism to act on the inner monad of your
StateT
. That is, we want a function which given a mapping from one monad to another (e.g. ourgeneralize
morphism), will give us a function acting on the base monad of a monad transformer, e.g.t Identity a -> t m a
. You'll find this resembles thehoist
function ofmmorph
'sMFunctor
class,Putting the pieces together,