I’ve got a bunch of stateful functions inside a State monad. At one point in the program there needs to be some IO actions so I’ve wrapped IO inside a StateT getting a pair of types like this:
mostfunctions :: State Sometype a
toplevel :: StateT Sometype IO a
To keep things simple I don’t want pass the IO context into the main set of functions and I would like to avoid wrapping them in the monad stack type. But in order to call them from the toplevel function I need something akin to a lift, but I’m not trying to lift a value from the inner monad. Rather I want to convert the state in the StateT monad into something equivalent in the State monad. To do this I’ve got the following:
wrapST :: (State Sometype a) -> StateT Sometype IO a
wrapST f = do s <- get
let (r,s2) = runState f s
put s2
return r
This then get used to interleave things like the following:
toplevel = do liftIO $ Some IO functions
wrapST $ Some state mutations
liftIO $ More IO functions
....
It seems like a fairly obvious block of code so I’m wondering does this function have a standard name, and it is already implemented somewhere in the standard libraries? I’ve tried to keep the description simple but obviously this extends to pulling one transformer out of a stack, converting the wrapped value to the cousin of the transformer type, skipping the monads below in the stack, and then pushing the results back in at the end.
It may be a good idea to refactor your code to use the type
StateT SomeType m ainstead ofState SomeType a, because the first one is compatible to an arbitrary monad stack. If you’d change it like this, you don’t need a functionwrapSTanymore, since you can call the stateful functions directly.Okay. Suppose you have a function
subOne :: Monad m => State Int Int:Now, change the types of all functions like this one from
State SomeType atoStateT SomeType m a, leavingmas is. This way, your functions can work on any monadic stack. For those functions, that require IO, you can specify, that the monad at the bottom must be IO:Now, it should be possible to use both functions together:
PS: I use GHC 7, some of the libs changed midway, so it might be a bit different on GHC 6.