mini-1.6.3.0: src/Mini/Random/Class.hs
-- | A pure interface for pseudorandom value generation
module Mini.Random.Class (
-- * Classes
Generator (
nextWord32,
nextWord64
),
Splittable (
split
),
Random (
random
),
-- * Operations
randoms,
) where
import Data.Bifunctor (
first,
)
import Data.Bits (
shiftL,
shiftR,
(.&.),
(.|.),
)
import Data.Int (
Int16,
Int32,
Int64,
Int8,
)
import Data.List (
unfoldr,
)
import Data.Word (
Word,
Word16,
Word32,
Word64,
Word8,
)
import Mini.Hash.Murmur32 (
Hash32,
add,
digest,
)
import Mini.Random.SplitMix (
SplitMix,
)
import qualified Mini.Random.SplitMix as SplitMix (
nextWord32,
nextWord64,
split,
)
import Prelude (
Bool,
Char,
Double,
Float,
Int,
Integer,
Maybe (
Just
),
fromIntegral,
odd,
toEnum,
(.),
(/),
)
-- Classes
-- | The class of pseudorandom number generators
class Generator g where
nextWord32 :: g -> (Word32, g)
nextWord32 = first fromIntegral . nextWord64
nextWord64 :: g -> (Word64, g)
instance Generator Hash32 where
nextWord32 h = let d = digest h in (d, add d h)
nextWord64 h =
let (lo, g) = nextWord32 h
(hi, g') = nextWord32 g
lo' = fromIntegral lo
hi' = fromIntegral hi `shiftL` 32
in (lo' .|. hi', g')
instance Generator SplitMix where
nextWord32 = SplitMix.nextWord32
nextWord64 = SplitMix.nextWord64
-- | The class of splittable pseudorandom number generators
class (Generator g) => Splittable g where
split :: g -> (g, g)
instance Splittable SplitMix where
split = SplitMix.split
-- | The class of types for which pseudorandom values can be generated
class Random a where
random :: (Generator g) => g -> (a, g)
instance Random Bool where
random = first odd . nextWord32
-- | Limited to 7-bit values (ASCII)
instance Random Char where
random = first (toEnum . fromIntegral . (.&. 0x7F)) . nextWord32
instance Random Int8 where
random = first fromIntegral . nextWord32
instance Random Int16 where
random = first fromIntegral . nextWord32
instance Random Int32 where
random = first fromIntegral . nextWord32
instance Random Int64 where
random = first fromIntegral . nextWord64
-- | Limited to 64-bit values
instance Random Int where
random = first (fromIntegral . (fromIntegral :: Word64 -> Int64)) . nextWord64
-- | Limited to 64-bit values
instance Random Integer where
random = first (fromIntegral . (fromIntegral :: Word64 -> Int64)) . nextWord64
instance Random Word8 where
random = first fromIntegral . nextWord32
instance Random Word16 where
random = first fromIntegral . nextWord32
instance Random Word32 where
random = nextWord32
instance Random Word64 where
random = nextWord64
-- | Limited to 64-bit values
instance Random Word where
random = first fromIntegral . nextWord64
-- | Limited to values in the semi-open interval [0, 1)
instance Random Float where
random = first go . nextWord32
where
go w =
let w24 = w `shiftR` 8
b24 = 1 `shiftL` 24 :: Word32
in fromIntegral w24 / fromIntegral b24
-- | Limited to values in the semi-open interval [0, 1)
instance Random Double where
random = first go . nextWord64
where
go w =
let w53 = w `shiftR` 11
b53 = 1 `shiftL` 53 :: Word64
in fromIntegral w53 / fromIntegral b53
-- Operations
-- | Generate an infinite list of pseudorandom values
randoms :: (Random a, Generator g) => g -> [a]
randoms = unfoldr (Just . random)