random-fu-0.0.0.2: src/Data/Random/Source/PureMT.hs
{-
- ``Data/Random/Source/PureMT''
-}
{-# LANGUAGE
MultiParamTypeClasses,
FlexibleContexts, FlexibleInstances
#-}
module Data.Random.Source.PureMT where
import Data.Random.Source
import System.Random.Mersenne.Pure64
import Data.StateRef
import Data.Word
import Control.Monad.State
-- |Given a mutable reference to a 'PureMT' generator, we can make a
-- 'RandomSource' usable in any monad in which the reference can be modified.
--
-- For example, if @x :: TVar PureMT@, @getRandomWordsFromMTRef x@ can be
-- used as a 'RandomSource' in 'IO', 'STM', or any monad which is an instance
-- of 'MonadIO'.
getRandomWordsFromMTRef :: ModifyRef sr m PureMT => sr -> Int -> m [Word64]
getRandomWordsFromMTRef ref n = do
atomicModifyRef ref (randomWords n [])
where
swap (a,b) = (b,a)
randomWords 0 ws mt = (mt, ws)
randomWords (n+1) ws mt = case randomWord64 mt of
(w, mt) -> randomWords n (w:ws) mt
-- |Similarly, @getRandomWordsFromMTState x@ can be used in any \"state\"
-- monad in the mtl sense whose state is a 'PureMT' generator.
-- Additionally, the standard mtl state monads have 'MonadRandom' instances
-- which do precisely that, allowing an easy conversion of 'RVar's and
-- other 'Distribution' instances to \"pure\" random variables.
getRandomWordsFromMTState :: MonadState PureMT m => Int -> m [Word64]
getRandomWordsFromMTState n = do
mt <- get
let randomWords 0 ws mt = (mt, ws)
randomWords (n+1) ws mt = case randomWord64 mt of
(w, mt) -> randomWords n (w:ws) mt
(newMt, ws) = randomWords n [] mt
put newMt
return ws
instance MonadRandom (State PureMT) where
getRandomWords = getRandomWordsFromMTState
instance Monad m => MonadRandom (StateT PureMT m) where
getRandomWords = getRandomWordsFromMTState