I have a simple function using Control.Monad.Random
to create a function which can sample a random number.
import Control.Monad.Random
import Data.Random
unif_bound :: (RandomGen g, Monad m) => Double -> Double -> RandT g m Double
unif_bound lb ub = getRandomR (lb,ub)
And, I run this to generate random numbers in GHCI as:
> gen <- newStdGen
> runRandT (unif_bound 1.0 3.0) gen
(1.7569726469904563,1700403094 44073136)
> runRandT (unif_bound 3.0, 1.0) gen
(1.7569726469904563,1700403094 44073136)
However, I would like to modify this code to check that lb < ub
, and wrap this in a MaybeT. The idea is that sampling where lb > ub
should return Nothing
. I realize that this is where monad transformers come in, but I have never used one before and not sure where to start.
For reference, RandT
is defined as
-- | A monad transformer which adds a random number generator to an
-- existing monad.
newtype RandT g m a = RandT (StateT g m a)
deriving (Functor, Monad, MonadTrans, MonadIO, MonadFix, MonadReader r, MonadWriter w)
Thanks!
You can generalize the type of your function quite a bit:
unif_bound :: (Random a, Ord a, MonadRandom m) => a -> a -> MaybeT m a
unif_bound lb ub | lb > ub = MaybeT (return Nothing)
| otherwise = getRandomR (lb,ub)
Note that you could replace MaybeT (return Nothing)
with fail ""
because that is how fail is defined in the monad instance for MaybeT m
, but this isn't very nice. Usage:
>runMaybeT $ unif_bound 1 10
Just 2
>runMaybeT $ unif_bound 400 1
Nothing
IO
is an instance of MonadRandom
, so you don't need to fiddle with RandT
if you are just testing in the interpreter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With