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.

+3


source to share


1 answer


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 library mtl

    to simplify it. The idea here is that if you write your action State

    only in terms of get

    , put

    and modify

    , 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

    and StateT s IO a

    . Moreover, since it specializes in type State s a

    , you can be sure that it doesn’t do anything IO

    or anything that State s a

    it couldn’t do, so you will get the same behavioral guarantees.

+7


source







All Articles