packages feed

random-source 0.3.0.10 → 0.3.0.11

raw patch · 6 files changed

+278/−140 lines, 6 filesdep ~mtldep ~randomnew-uploader

Dependency ranges changed: mtl, random

Files

+ changelog.md view
@@ -0,0 +1,13 @@+* Changes in 0.3.0.11: Revert 0.3.0.10 changes (which accidentally removed the Random.Source.PureMT module and added an overlapping instance).++* Changes in 0.3.0.8: Add MonadRandom instance for MWC generator and RWS transformer.++* Changes in 0.3.0.6: Fixed overzealous fix in 0.3.0.5.  The people responsible for sacking the people who have been sacked, etc., have been sacked.++* Changes in 0.3.0.5: Renamed some internal modules and accidentally some external ones too.  Whoops.  Please don't use this version, it will only end in tears.++* Changes in 0.3.0.4: Fixed a typo that broke building with MTL-1++* Changes in 0.3.0.3: Fixes for GHC's deprecation of Foreign.unsafePerformIO++* Changes in 0.3.0.2: Fixes for GHC 7.2.*'s crazy Template Haskell changes.
random-source.cabal view
@@ -1,5 +1,5 @@ name:                   random-source-version:                0.3.0.10+version:                0.3.0.11 stability:              provisional  cabal-version:          >= 1.10@@ -18,22 +18,11 @@                         \"completing\" partial implementations, making it                         easy to define new entropy sources in a way that                         is naturally forward-compatible.-                        .-                        Changes in 0.3.0.6: Fixed overzealous fix in 0.3.0.5.  The people responsible for sacking the people who have been sacked, etc., have been sacked.-                        .-                        Changes in 0.3.0.5: Renamed some internal modules and accidentally some external ones too.  Whoops.  Please don't use this version, it will only end in tears.-                        .-                        Changes in 0.3.0.4: Fixed a typo that broke building-                        with MTL-1-                        .-                        Changes in 0.3.0.3: Fixes for GHC's deprecation-                        of Foreign.unsafePerformIO-                        .-                        Changes in 0.3.0.2: Fixes for GHC 7.2.*'s crazy-                        Template Haskell changes.  tested-with:            GHC == 7.4.2, GHC == 7.6.1 +extra-source-files:     changelog.md+ source-repository head   type:                 git   location:             https://github.com/mokus0/random-fu.git@@ -51,14 +40,14 @@   default-language:     Haskell2010   exposed-modules:      Data.Random.Source                         Data.Random.Source.IO-                        Data.Random.Source.RandomGen+                        Data.Random.Source.PureMT                         Data.Random.Source.Std                         Data.Random.Source.StdGen                         Data.Random.Internal.Words                         Data.Random.Internal.Source   other-modules:        Data.Random.Source.Internal.Prim                         Data.Random.Source.Internal.TH-+     if impl(ghc >= 6.10)     -- mwc-random depends on vector, which doesn't build on GHC < 6.10.     -- I considered breaking this module out into another package, but I@@ -69,21 +58,21 @@     -- this cabal file is hardly any additional effort.     exposed-modules:    Data.Random.Source.MWC     build-depends:      mwc-random-+       if flag(mtl2)     build-depends:      mtl == 2.*     cpp-options:        -DMTL2   else     build-depends:      mtl == 1.*-+     if flag(base4)     build-depends:      base >= 4 && <5, syb   else     build-depends:      base >= 3 && <4-+     build-depends:        flexible-defaults >= 0.0.0.2,                         mersenne-random-pure64,-                        random >= 1.2.0,+                        random >= 1.2.0 && < 1.3,                         stateref >= 0.3 && < 0.4,                         template-haskell,                         th-extras,
src/Data/Random/Source.hs view
@@ -11,7 +11,7 @@         , getRandomDouble         , getRandomNByteInteger         )-+         , RandomSource         ( getRandomWord8From         , getRandomWord16From@@ -20,7 +20,7 @@         , getRandomDoubleFrom         , getRandomNByteIntegerFrom         )-+         , monadRandom, randomSource     ) where @@ -30,7 +30,7 @@ import Data.Random.Source.Internal.TH  $(randomSource-    [d|+    [d|          instance Monad m => RandomSource m (m Word8) where             getRandomWord8From = id      |])
+ src/Data/Random/Source/PureMT.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell, GADTs #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- |This module provides functions useful for implementing new 'MonadRandom'+-- and 'RandomSource' instances for state-abstractions containing 'PureMT'+-- values (the pure pseudorandom generator provided by the+-- mersenne-random-pure64 package), as well as instances for some common+-- cases.+-- +-- A 'PureMT' generator is immutable, so 'PureMT' by itself cannot be a +-- 'RandomSource' (if it were, it would always give the same \"random\"+-- values).  Some form of mutable state must be used, such as an 'IORef',+-- 'State' monad, etc..  A few default instances are provided by this module+-- along with a more-general function ('getRandomPrimFromMTRef') usable as+-- an implementation for new cases users might need.+module Data.Random.Source.PureMT +    ( PureMT, newPureMT, pureMT+    +    , getRandomPrimFromMTRef+    ) where++import Control.Monad.State+import Control.Monad.RWS+import qualified Control.Monad.State.Strict as S+import qualified Control.Monad.RWS.Strict as S+import Data.Random.Internal.Source+import Data.Random.Source.Internal.TH+import Data.StateRef+import System.Random.Mersenne.Pure64++{-# INLINE withMTRef #-}+withMTRef :: (Monad m, ModifyRef sr m PureMT) => (PureMT -> (t, PureMT)) -> sr -> m t+withMTRef thing ref = atomicModifyReference ref $ \(!oldMT) -> +    case thing oldMT of (!w, !newMT) -> (newMT, w)++{-# INLINE withMTState #-}+withMTState :: MonadState PureMT m => (PureMT -> (t, PureMT)) -> m t+withMTState thing = do+    !mt <- get+    let (!ws, !newMt) = thing mt+    put newMt+    return ws++#ifndef MTL2++$(monadRandom+    [d| instance MonadRandom (State PureMT) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance MonadRandom (S.State PureMT) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance Monoid w => MonadRandom (RWS r w PureMT) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance Monoid w => MonadRandom (S.RWS r w PureMT) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++#endif++$(randomSource+    [d| instance (Monad m1, ModifyRef (Ref m2 PureMT) m1 PureMT) => RandomSource m1 (Ref m2 PureMT) where+            getRandomWord64From = withMTRef randomWord64+            getRandomDoubleFrom = withMTRef randomDouble+    |])++$(monadRandom+    [d| instance Monad m => MonadRandom (StateT PureMT m) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance Monad m => MonadRandom (S.StateT PureMT m) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance (Monad m, Monoid w) => MonadRandom (RWST r w PureMT m) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(monadRandom+    [d| instance (Monad m, Monoid w) => MonadRandom (S.RWST r w PureMT m) where+            getRandomWord64 = withMTState randomWord64+            getRandomDouble = withMTState randomDouble+     |])++$(randomSource+    [d| instance (MonadIO m) => RandomSource m (IORef PureMT) where+            getRandomWord64From = withMTRef randomWord64+            getRandomDoubleFrom = withMTRef randomDouble+     |])++$(randomSource+    [d| instance (Monad m, ModifyRef (STRef s PureMT) m PureMT) => RandomSource m (STRef s PureMT) where+            getRandomWord64From = withMTRef randomWord64+            getRandomDoubleFrom = withMTRef randomDouble+     |])++-- Note that this instance is probably a Bad Idea.  STM allows random variables+-- to interact in spooky quantum-esque ways - One transaction can 'retry' until+-- it gets a \"random\" answer it likes, which causes it to selectively consume +-- entropy, biasing the supply from which other random variables will draw.+-- instance (Monad m, ModifyRef (TVar PureMT) m PureMT) => RandomSource m (TVar PureMT) where+--     {-# SPECIALIZE instance RandomSource IO  (TVar PureMT) #-}+--     {-# SPECIALIZE instance RandomSource STM (TVar PureMT) #-}+--     getRandomPrimFrom = getRandomPrimFromMTRef+++-- |Given a mutable reference to a 'PureMT' generator, we can implement+-- 'RandomSource' for it in any monad in which the reference can be modified.+-- +-- Typically this would be used to define a new 'RandomSource' instance for+-- some new reference type or new monad in which an existing reference type+-- can be modified atomically.  As an example, the following instance could+-- be used to describe how 'IORef' 'PureMT' can be a 'RandomSource' in the+-- 'IO' monad:+-- +-- > instance RandomSource IO (IORef PureMT) where+-- >     supportedPrimsFrom _ _ = True+-- >     getSupportedRandomPrimFrom = getRandomPrimFromMTRef+-- +-- (note that there is actually a more general instance declared already+-- covering this as a a special case, so there's no need to repeat this+-- declaration anywhere)+-- +-- Example usage (using some functions from "Data.Random" in the random-fu +-- package):+-- +-- > main = do+-- >     src <- newIORef (pureMT 1234)          -- OR: newPureMT >>= newIORef+-- >     x <- runRVar (uniform 0 100) src :: IO Double+-- >     print x+getRandomPrimFromMTRef :: ModifyRef sr m PureMT => sr -> Prim a -> m a+getRandomPrimFromMTRef ref+    = atomicModifyReference' ref +    . runState +    . getRandomPrim++atomicModifyReference' :: ModifyRef sr m a => sr -> (a -> (b, a)) -> m b+atomicModifyReference' ref getR =+    atomicModifyReference ref (swap' . getR)+        where swap' (!a,!b) = (b,a)
− src/Data/Random/Source/RandomGen.hs
@@ -1,106 +0,0 @@--{-# LANGUAGE-    CPP,-    MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, GADTs,-    BangPatterns, RankNTypes,-    ScopedTypeVariables-  #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}---- |This module provides functions useful for implementing new 'MonadRandom'--- and 'RandomSource' instances for state-abstractions containing over 'RandomGen'--- instance (the type class for pseudorandom generators provided by the System.Random--- module in the \"random\" package), as well as instances for some common--- cases.-module Data.Random.Source.RandomGen-    ( getRandomPrimFromRandomGenRef-    , getRandomPrimFromRandomGenState-    ) where--import Data.Random.Internal.Source-import System.Random-import Control.Monad.State-import Control.Monad.RWS-import qualified Control.Monad.State.Strict as S-import qualified Control.Monad.RWS.Strict as S-import Data.StateRef-import Data.Word---instance (Monad m1, RandomGen g, ModifyRef (Ref m2 g) m1 g) => RandomSource m1 (Ref m2 g) where-    getRandomPrimFrom = getRandomPrimFromRandomGenRef--instance (Monad m, RandomGen g, ModifyRef (IORef g) m g) => RandomSource m (IORef g) where-    {-# SPECIALIZE instance RandomSource IO (IORef StdGen) #-}-    getRandomPrimFrom = getRandomPrimFromRandomGenRef---- |Given a mutable reference to a 'RandomGen' generator, we can make a--- 'RandomSource' usable in any monad in which the reference can be modified.-getRandomPrimFromRandomGenRef :: (Monad m, ModifyRef sr m g, RandomGen g) =>-                                  sr -> Prim a -> m a-getRandomPrimFromRandomGenRef ref-    = atomicModifyReference' ref-    . runState-    . getRandomPrimFromRandomGenState--atomicModifyReference' :: ModifyRef sr m a => sr -> (a -> (b, a)) -> m b-atomicModifyReference' ref getR =-    atomicModifyReference ref (swap' . getR)-        where swap' (!a,!b) = (b,a)----- |Similarly, @getRandomWordFromRandomGenState x@ can be used in any \"state\"--- monad in the mtl sense whose state is a 'RandomGen' 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.-getRandomPrimFromRandomGenState :: forall g m a. (RandomGen g, MonadState g m) => Prim a -> m a-getRandomPrimFromRandomGenState = genPrim-    where-        {-# INLINE genPrim #-}-        genPrim :: forall t. Prim t -> m t-        genPrim PrimWord8            = getThing (randomR (0, 0xff))                (fromIntegral :: Int -> Word8)-        genPrim PrimWord16           = getThing (randomR (0, 0xffff))              (fromIntegral :: Int -> Word16)-        genPrim PrimWord32           = getThing (randomR (0, 0xffffffff))          (fromInteger)-        genPrim PrimWord64           = getThing (randomR (0, 0xffffffffffffffff))  (fromInteger)-        genPrim PrimDouble           = getThing (randomR (0, 0x000fffffffffffff))  (flip encodeFloat (-52))-          {- not using the Random Double instance for 2 reasons.  1st, it only generates 32 bits of entropy, when-             a [0,1) Double has room for 52.  Second, it appears there's a bug where it can actually generate a-             negative number in the case where randomIvalInteger returns minBound::Int32. -}---        genPrim PrimDouble = getThing (randomR (0, 1.0))  (id)-        genPrim (PrimNByteInteger n) = getThing (randomR (0, iterate (*256) 1 !! n)) id--        {-# INLINE getThing #-}-        getThing :: forall b t. (g -> (b, g)) -> (b -> t) -> m t-        getThing thing f = do-            !oldGen <- get-            case thing oldGen of-                (!i,!newGen) -> do-                    put newGen-                    return (f $! i)--#ifndef MTL2-instance RandomGen g => MonadRandom (State g) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance RandomGen g => MonadRandom (S.State g) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance (RandomGen g, Monoid w) => MonadRandom (RWS r w g) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance (RandomGen g, Monoid w) => MonadRandom (S.RWS r w g) where-    getRandomPrim = getRandomPrimFromRandomGenState-#endif--instance (RandomGen g, Monad m) => MonadRandom (StateT g m) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance (RandomGen g, Monad m) => MonadRandom (S.StateT g m) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance (RandomGen g, Monad m, Monoid w) => MonadRandom (RWST r w g m) where-    getRandomPrim = getRandomPrimFromRandomGenState--instance (RandomGen g, Monad m, Monoid w) => MonadRandom (S.RWST r w g m) where-    getRandomPrim = getRandomPrimFromRandomGenState
src/Data/Random/Source/StdGen.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE+    CPP,     MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, GADTs,     BangPatterns, RankNTypes,     ScopedTypeVariables@@ -14,23 +15,33 @@     ( StdGen     , mkStdGen     , newStdGen-+         , getRandomPrimFromStdGenIO-    , RandomGen.getRandomPrimFromRandomGenRef-    , RandomGen.getRandomPrimFromRandomGenState+    , getRandomPrimFromRandomGenRef+    , getRandomPrimFromRandomGenState     ) where  import Data.Random.Internal.Source-import qualified Data.Random.Source.RandomGen as RandomGen import System.Random import Control.Monad.State+import Control.Monad.RWS import qualified Control.Monad.ST.Strict as S+import qualified Control.Monad.State.Strict as S+import qualified Control.Monad.RWS.Strict as S import Data.StateRef+import Data.Word  +instance (Monad m1, ModifyRef (Ref m2 StdGen) m1 StdGen) => RandomSource m1 (Ref m2 StdGen) where+    getRandomPrimFrom = getRandomPrimFromRandomGenRef++instance (Monad m, ModifyRef (IORef   StdGen) m StdGen) => RandomSource m (IORef   StdGen) where+    {-# SPECIALIZE instance RandomSource IO (IORef StdGen) #-}+    getRandomPrimFrom = getRandomPrimFromRandomGenRef+ -- Note that this instance is probably a Bad Idea.  STM allows random variables -- to interact in spooky quantum-esque ways - One transaction can 'retry' until--- it gets a \"random\" answer it likes, which causes it to selectively consume+-- it gets a \"random\" answer it likes, which causes it to selectively consume  -- entropy, biasing the supply from which other random variables will draw. -- instance (Monad m, ModifyRef (TVar    StdGen) m StdGen) => RandomSource m (TVar    StdGen) where --     {-# SPECIALIZE instance RandomSource IO  (TVar StdGen) #-}@@ -41,22 +52,91 @@ instance (Monad m, ModifyRef (STRef s StdGen) m StdGen) => RandomSource m (STRef s StdGen) where     {-# SPECIALIZE instance RandomSource (ST s) (STRef s StdGen) #-}     {-# SPECIALIZE instance RandomSource (S.ST s) (STRef s StdGen) #-}-    getRandomPrimFrom = RandomGen.getRandomPrimFromRandomGenRef+    getRandomPrimFrom = getRandomPrimFromRandomGenRef  getRandomPrimFromStdGenIO :: Prim a -> IO a-getRandomPrimFromStdGenIO+getRandomPrimFromStdGenIO      = getStdRandom     . runState     . getRandomPrim +-- |Given a mutable reference to a 'RandomGen' generator, we can make a+-- 'RandomSource' usable in any monad in which the reference can be modified.+-- +-- See "Data.Random.Source.PureMT".'getRandomPrimFromMTRef' for more detailed+-- usage hints - this function serves exactly the same purpose except for a+-- 'StdGen' generator instead of a 'PureMT' generator.+getRandomPrimFromRandomGenRef :: (Monad m, ModifyRef sr m g, RandomGen g) =>+                                  sr -> Prim a -> m a+getRandomPrimFromRandomGenRef ref +    = atomicModifyReference' ref +    . runState +    . getRandomPrimFromRandomGenState++atomicModifyReference' :: ModifyRef sr m a => sr -> (a -> (b, a)) -> m b+atomicModifyReference' ref getR =+    atomicModifyReference ref (swap' . getR)+        where swap' (!a,!b) = (b,a)++ -- |Similarly, @getRandomWordFromRandomGenState x@ can be used in any \"state\" -- monad in the mtl sense whose state is a 'RandomGen' 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.---+--  -- Again, see "Data.Random.Source.PureMT".'getRandomPrimFromMTState' for more--- detailed usage hints - this function serves exactly the same purpose except+-- detailed usage hints - this function serves exactly the same purpose except  -- for a 'StdGen' generator instead of a 'PureMT' generator.-{-# SPECIALIZE RandomGen.getRandomPrimFromRandomGenState :: Prim a -> State StdGen a #-}-{-# SPECIALIZE RandomGen.getRandomPrimFromRandomGenState :: Monad m => Prim a -> StateT StdGen m a #-}+{-# SPECIALIZE getRandomPrimFromRandomGenState :: Prim a -> State StdGen a #-}+{-# SPECIALIZE getRandomPrimFromRandomGenState :: Monad m => Prim a -> StateT StdGen m a #-}+getRandomPrimFromRandomGenState :: forall g m a. (RandomGen g, MonadState g m) => Prim a -> m a+getRandomPrimFromRandomGenState = genPrim+    where +        {-# INLINE genPrim #-}+        genPrim :: forall t. Prim t -> m t+        genPrim PrimWord8            = getThing (randomR (0, 0xff))                (fromIntegral :: Int -> Word8)+        genPrim PrimWord16           = getThing (randomR (0, 0xffff))              (fromIntegral :: Int -> Word16)+        genPrim PrimWord32           = getThing (randomR (0, 0xffffffff))          (fromInteger)+        genPrim PrimWord64           = getThing (randomR (0, 0xffffffffffffffff))  (fromInteger)+        genPrim PrimDouble           = getThing (randomR (0, 0x000fffffffffffff))  (flip encodeFloat (-52))+          {- not using the Random Double instance for 2 reasons.  1st, it only generates 32 bits of entropy, when +             a [0,1) Double has room for 52.  Second, it appears there's a bug where it can actually generate a +             negative number in the case where randomIvalInteger returns minBound::Int32. -}+--        genPrim PrimDouble = getThing (randomR (0, 1.0))  (id)+        genPrim (PrimNByteInteger n) = getThing (randomR (0, iterate (*256) 1 !! n)) id+        +        {-# INLINE getThing #-}+        getThing :: forall b t. (g -> (b, g)) -> (b -> t) -> m t+        getThing thing f = do+            !oldGen <- get+            case thing oldGen of+                (!i,!newGen) -> do+                    put newGen+                    return (f $! i)++#ifndef MTL2+instance MonadRandom (State StdGen) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance MonadRandom (S.State StdGen) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance Monoid w => MonadRandom (RWS r w StdGen) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance Monoid w => MonadRandom (S.RWS r w StdGen) where+    getRandomPrim = getRandomPrimFromRandomGenState+#endif++instance Monad m => MonadRandom (StateT StdGen m) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance Monad m => MonadRandom (S.StateT StdGen m) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance (Monad m, Monoid w) => MonadRandom (RWST r w StdGen m) where+    getRandomPrim = getRandomPrimFromRandomGenState++instance (Monad m, Monoid w) => MonadRandom (S.RWST r w StdGen m) where+    getRandomPrim = getRandomPrimFromRandomGenState