简体   繁体   中英

Combining StateT and State monads

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:

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 .

What you are asking for is a mapping (known as a monad morphism) from a monad StateT m to StateT n . I'll be using the the mmorph 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 the Identity monad embedded in State ,

generalize :: Monad m => Identity a -> m a
generalize = return . runIdentity

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 (eg our generalize morphism), will give us a function acting on the base monad of a monad transformer, eg t Identity a -> tma . You'll find this resembles the hoist function of mmorph 's MFunctor class,

hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

Putting the pieces together,

myAction :: State s Int
myAction = return 2

myAction' :: Monad m => StateT s m Int
myAction' = hoist generalize myAction

Such a function is not definable for all monad transformers. The Cont r monad, for example, can't be lifted into ContT r IO because that would require turning a continuation in the IO monad ( a -> IO r ) into a pure continuation ( a -> r ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM