Lift to anchor * inside * the monad transformer stack
Suppose I have IO Int
it wrapped in StateT MyState
, then I have the value State MyState Int
that I want to use in the stacked monad. How to raise it in this internal sense? I already know to use lift
or liftIO
, if I get something compatible with the inner one, that I just need to hoist to the outer monad, but now I have the opposite problem: the value is already in the outer monad, but not the inner one.
For example:
checkSame :: State MyState a -> IO a -> StateT MyState IO Bool
checkSame sim real = do
rres <- liftIO real
sres <- ??? sim
return $ rres == sres
Do I have to "get" the state, drag it through runState manually and add it again, or is there some general way to do this?
BTW, this sim parameter is a whole bunch of state functions that have nothing to do with IO, so I'm a little reluctant to make them all return StateT MyState IO a
if I can avoid it.
source to share
You have two options:
- Find the morphism of the monad. This often depends on finding the correct library; in this case hoist and generalize together should get where you need to go.
-
Make the action
State
more polymorphic. It is commonly used and recommended; it boils down to a preliminary application of the morphism from part 1, but it has many mechanisms already installed in the librarymtl
to simplify it. The idea here is that if you write your actionState
only in terms ofget
,put
andmodify
, then instead of a type,State s a
you can give it a type:MonadState s m => m a
Then later on the site call, you can choose any Monad for this, including both
State s a
andStateT s IO a
. Moreover, since it specializes in typeState s a
, you can be sure that it doesnβt do anythingIO
or anything thatState s a
it couldnβt do, so you will get the same behavioral guarantees.
source to share