Just learning how to get a deeper intuitive grasp of monads and transformers; a lot of things that might seem obvious are still kind of tricky to me haha.
So I have a computation that lives in the Rand
monad, but inside it, there is another "sub-computation" (or multiple) that lives inside an ST
monad (or State
monad, for all it matters ... ST
only for performance but I think State
works just as well in this context).
The entire computation doesn't need to be inside the ST
monad...and this sub-computation will be called multiple times with different starting states, so I don't want to coerce the entire thing into an ST
(unless that's the idiomatic way).
Without randomness, the structure looks like this:
main = print mainComp
mainComp :: Int
mainComp = otherComp + (subComp 1) + (subComp 2)
subComp :: Int -> Int
subComp n = runST $ do
-- generate state based on n
-- ...
replicateM_ 100 mutateState
-- ...
-- eventually returns an ST s Int
mutateState :: ST s ()
mutateState = -- ...
Basically things work pretty well and there is complete referential transparency in mainComp
and subComp
.
This is how I've so far used Rand
--
main = (evalRandIO mainComp) >>= print
mainComp :: (RandomGen g) => Rand g Int
mainComp = do
subResultA <- subComp 1
subResultB <- subComp 2
return $ otherComp + subResultA + subResultB
subComp :: (RandomGen g) => Int -> Rand g Int
subComp = return $ runST $ do -- is this ok to just throw in return?
-- generate state based on n
-- ...
replicateM_ 100 mutateState
-- ...
-- eventually returns an ST s Int (??)
mutateState :: ??
mutateState = ??
What is the type of mutateState
supposed to be, if I wanted to use the random seed and the Rand
monad in it? I think I might want to use a return type of RandT g (ST s) ()
, but how do I make that fit in with the type expected in the runST
in subComp
?