Search code examples
haskellmonadsstate-monad

How to share state between two monads?


I am stuck with following monad problem:

Let's say I have a standard monad State with state S = (LS, RS). I also have another monad:

newtype StateP a = StateP {runP :: S -> (a, RS)}

I want to perform some computation using StateP then merge state with state in State monad:

merge m :: StateP() -> State()
merge m = do
 s@(l,r) <- get
 put (l, snd (runP m s))

It is not working, but I don't get why? Is there another way to achieve such functionality?


Solution

  • You can use monad transformers to model these requirements more explicitly using two monad stacks: one that can only read LS and one that can both read and write LS.

    type ReadOnlyLS a  = ReaderT LS (State RS) a
    type ReadWriteLS a = StateT LS (State RS) a
    

    To run a ReadOnlyLS within ReadWriteLS, we just need to extract LS from the outermost state layer, give it to the reader layer of the inner computation and lift the resulting computation back into the outer monad:

    merge :: ReadOnlyLS a -> ReadWriteLS a
    merge m = get >>= lift . runReaderT m