I want to use do notation to combine pseudo-random values:
g :: StdGen
g = mkStdGen 100
example1 :: Bool
example1
= fst
$ runState
(do x <- state (uniformR (False,True))
y <- state (uniformR (False,True))
return $ x == y
)
g
uniformR is defined in terms of the System.Random.Stateful module:
uniformR :: (RandomGen g, UniformRange a) => (a, a) -> g -> (a, g)
uniformR r g = runStateGen g (uniformRM r)
so in my example, it seems silly for uniformR to create and run state, only for my example to create and run state again.
Is there a way to rewrite example1, using System.Random.Stateful and do notation?
This is the only thing I could get to work (which is ridiculous):
example3 :: Bool
example3
= fst
$ runStateGen
g
(do x <- uniformRM (False,True)
y <- uniformRM (False,True)
return $ do x' <- x
y' <- y
return $ x'==y')
It seems like what I need is some type of monad transformer?
CodePudding user response:
The second argument to runStateGen
is StateGenM g -> State g a
, which is ReaderT
in disguise:
import Control.Monad.Reader (ReaderT(..), runReaderT)
import Control.Applicative (liftA2)
import qualified System.Random.Stateful as Random
uniformRM :: (Random.UniformRange a, Random.StatefulGen g m) => (a, a) -> ReaderT g m a
uniformRM r = ReaderT (Random.uniformRM r)
g :: Random.StdGen
g = Random.mkStdGen 100
example1
= Random.runStateGen_ g
$ runReaderT
$ liftA2 (==) (uniformRM (False,True)) (uniformRM (False,True))
CodePudding user response:
It is much simpler than one would imagine:
example4 :: Bool
example4 = runStateGen_ (mkStdGen 100) $ \gen -> do
x <- uniformRM (False,True) gen
y <- uniformRM (False,True) gen
pure (x == y)
Of course uniformRM (False, True) == unformM
, but that is probably irrelevant, since that was just an example to demonstrate the question, I imagine.
More info can be found in haddock as well as in this blogpost and this video presentation