How to share state between two monads?
-
21-02-2021 - |
Question
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
OTHER TIPS
On the off-chance that your code is nearly right, try
merge :: StateP() -> State()
merge m = do
s@(l,r) <- get
put (l, snd (runP m s))
But you need to give us more details really.
How do you achieve the functionality of RunP? Do you redefine a monad instance for it and have getP/putP? Your code seems fine, can you provide the m you use? What kind of misbehaviour do you get?