I have created this monadic computation that works with both state and randomness:
import Control.Monad.State
import Control.Monad.Identity
import Control.Monad.Random.Class
-- coin flip function
coinFlip :: MonadRandom m => m Bool
coinFlip = (< 0.5) <$> getRandomR (0,1 :: Double)
-- main computation I want to execute
myComputation :: (MonadState Bool m, MonadRandom m) => m Bool
myComputation = coinFlip >>= \result -> put result >> return result
I need help figuring out the proper way to execute myComputation. The goal is to make sure it returns True approximately 50% of the time when run multiple times. What’s the correct approach to run this type of computation that requires both state and random number generation?
You need a monad transformer stack with both MonadState and MonadRandom instances. Use StateT with RandT from the MonadRandom package.
Here’s how I usually do it:
import Control.Monad.State
import Control.Monad.Random
import System.Random
runMyComputation :: IO (Bool, Bool)
runMyComputation = do
gen <- newStdGen
return $ evalRand (runStateT myComputation False) gen
This gives you a StateT Bool (Rand StdGen) stack that handles both state management and random generation. evalRand runs the random computation with a generator, runStateT manages the state. Run this in a loop multiple times to test the distribution.
You can also flip it and use RandT on the outside with StateT inside. I like this setup better for some cases:
import Control.Monad.Random
import Control.Monad.State
runComputation :: IO Bool
runComputation = do
gen <- getStdGen
let (result, _) = runRand (evalStateT myComputation False) gen
return result
Now your stack is RandT (StateT Bool Identity) instead. Both ways work the same, but this version chains multiple random computations more smoothly. Want to check the distribution? Run replicateM 1000 runComputation and count the True values.