module Foundation.Random.DRG ( RandomGen(..) , MonadRandomState(..) , withRandomGenerator ) where import Basement.Imports import Foundation.Random.Class -- | A Deterministic Random Generator (DRG) class class RandomGen gen where -- | Initialize a new random generator randomNew :: MonadRandom m => m gen -- | Initialize a new random generator from a binary seed. -- -- If `Nothing` is returned, then the data is not acceptable -- for creating a new random generator. randomNewFrom :: UArray Word8 -> Maybe gen -- | Generate N bytes of randomness from a DRG randomGenerate :: CountOf Word8 -> gen -> (UArray Word8, gen) -- | Generate a Word64 from a DRG randomGenerateWord64 :: gen -> (Word64, gen) randomGenerateF32 :: gen -> (Float, gen) randomGenerateF64 :: gen -> (Double, gen) -- | A simple Monad class very similar to a State Monad -- with the state being a RandomGenerator. newtype MonadRandomState gen a = MonadRandomState { runRandomState :: gen -> (a, gen) } instance Functor (MonadRandomState gen) where fmap f m = MonadRandomState $ \g1 -> let (a, g2) = runRandomState m g1 in (f a, g2) instance Applicative (MonadRandomState gen) where pure a = MonadRandomState $ \g -> (a, g) (<*>) fm m = MonadRandomState $ \g1 -> let (f, g2) = runRandomState fm g1 (a, g3) = runRandomState m g2 in (f a, g3) instance Monad (MonadRandomState gen) where return a = MonadRandomState $ \g -> (a, g) (>>=) m1 m2 = MonadRandomState $ \g1 -> let (a, g2) = runRandomState m1 g1 in runRandomState (m2 a) g2 instance RandomGen gen => MonadRandom (MonadRandomState gen) where getRandomBytes n = MonadRandomState (randomGenerate n) getRandomWord64 = MonadRandomState randomGenerateWord64 getRandomF32 = MonadRandomState randomGenerateF32 getRandomF64 = MonadRandomState randomGenerateF64 -- | Run a pure computation with a Random Generator in the 'MonadRandomState' withRandomGenerator :: RandomGen gen => gen -> MonadRandomState gen a -> (a, gen) withRandomGenerator gen m = runRandomState m gen