What is the Monad Stack feature called?

I have a bunch of state functions inside the state monad. At some point, the program should have some I / O, so I wrapped IO inside StateT, getting a couple of these types:

mostfunctions :: State Sometype a toplevel :: StateT Sometype IO a 

To keep things simple, I don’t want to pass the IO context into the main set of functions, and I would like to avoid wrapping them in the form of a monad stack. But in order to call them from the top-level function, I need something like an elevator, but I'm not trying to raise the value from the inner monad. Rather, I want to convert the state in the StateT monad to something equivalent in the state monad. For this, I have the following:

 wrapST :: (State Sometype a) -> StateT Sometype IO a wrapST f = do s <- get let (r,s2) = runState fs put s2 return r 

You will then use the following things to alternate:

 toplevel = do liftIO $ Some IO functions wrapST $ Some state mutations liftIO $ More IO functions .... 

This seems to be a pretty obvious block of code, so I wonder if this function has a standard name, and is it already implemented somewhere in standard libraries? I tried to keep the description simple, but obviously it expands the ability to pull one of the transformers from the stack, converting the wrapped value into a cousin like a transformer, skipping the monads below on the stack and then returning the results back to the end.

+7
source share
2 answers

It might be a good idea to reorganize your code to use StateT SomeType ma instead of State SomeType a , because the first one is compatible with an arbitrary monad stack. If you change it like this, you will no longer need the wrapST function, since you can directly call state functions.

Good. Suppose you have a function subOne :: Monad m => State Int Int :

 subOne = do a <- get put $ a - 1 return a 

Now change the types of all functions like this from State SomeType a to StateT SomeType ma , leaving m as it is. Thus, your functions can work with any monadic glass. For those functions that require I / O, you can specify that the monad at the bottom should be IO:

 printState :: MonadIO m => StateT Int m () printState = do a <- get liftIO $ print a 

Now you can use both functions together:

 -- You could use me without IO as well! subOne :: Monad m => StateT Int m () subOne = do a <- get put $ a - 1 printState :: MonadIO m => StateT Int m () printState = do a <- get liftIO $ print a toZero :: StateT Int IO () toZero = do subOne -- A really pure function printState -- function may perform IO a <- get when (a > 0) toZero 

PS: I use GHC 7, some of the libs change halfway, so in GHC 6 it can be a little different.

+9
source

A more direct answer to your question: the hoist function does exactly what you describe in a slightly more general way. Usage example:

 import Control.Monad.State import Data.Functor.Identity import Control.Monad.Morph foo :: State Int Integer foo = put 1 >> return 1 bar :: StateT Int IO Integer bar = hoist (return . runIdentity) foo 

hoist is part of the MFunctor class, which is defined as follows:

 class MFunctor t where hoist :: Monad m => (forall a. ma -> na) -> tmb -> tnb 

There are cases for most monad transformers, but not ContT .

+3
source

All Articles