{- - ``Data/Random/Source'' -} {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} module Data.Random.Source ( MonadRandom(..) , RandomSource(..) ) where import Data.Word import Data.Bits import Data.List import Data.Random.Internal.Words -- |A typeclass for monads with a chosen source of entropy. For example, -- 'RVar' is such a monad - the source from which it is (eventually) sampled -- is the only source from which a random variable is permitted to draw, so -- when directly requesting entropy for a random variable these functions -- are used. -- -- The minimal definition is either 'getRandomBytes' or 'getRandomWords'. class Monad m => MonadRandom m where -- |get the specified number of random (uniformly distributed) bytes getRandomBytes :: Int -> m [Word8] getRandomBytes n | n .&. 7 == 0 = do let wc = n `shiftR` 3 ws <- getRandomWords wc return (concatMap wordToBytes ws) | otherwise = do let wc = (n `shiftR` 3) + 1 ws <- getRandomWords wc return . take n . concatMap wordToBytes $ ws -- |alternate basis function, providing access to larger chunks getRandomWords :: Int -> m [Word64] getRandomWords n = do bs <- getRandomBytes (n `shiftL` 3) return (bytesToWords bs) -- |A source of entropy which can be used in the given monad. -- -- The minimal definition is either 'getRandomBytesFrom' or 'getRandomWordsFrom' class Monad m => RandomSource m s where getRandomBytesFrom :: s -> Int -> m [Word8] getRandomBytesFrom src n | n .&. 7 == 0 = do let wc = n `shiftR` 3 ws <- getRandomWordsFrom src wc return (concatMap wordToBytes ws) | otherwise = do let wc = (n `shiftR` 3) + 1 ws <- getRandomWordsFrom src wc return . take n . concatMap wordToBytes $ ws getRandomWordsFrom :: s -> Int -> m [Word64] getRandomWordsFrom src n = do bs <- getRandomBytesFrom src (n `shiftL` 3) return (bytesToWords bs) instance Monad m => RandomSource m (Int -> m [Word8]) where getRandomBytesFrom = id instance Monad m => RandomSource m (Int -> m [Word64]) where getRandomWordsFrom = id