{- - ``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