Bryan O'Sullivan avatar Bryan O'Sullivan committed bdee89e

Add asGenIO and addGenST, and improce docs.

This fixes gh-14.

Comments (0)

Files changed (1)

System/Random/MWC.hs

 -- The simplest use is to generate a vector of uniformly distributed values:
 --
 -- @
---   vs <- withSystemRandom (uniformVector 100)
+--   vs <- withSystemRandom . asGenST $ \gen -> uniformVector gen 100
 -- @
 --
--- These values can be of any type which is an instance of the class 'Variate'.
+-- These values can be of any type which is an instance of the class
+-- 'Variate'.
 --
--- To generate random values on demand, first 'create' a random number generator.
+-- To generate random values on demand, first 'create' a random number
+-- generator.
 --
 -- @
 --   gen <- create
 -- @
 --
--- Keep this generator and use it wherever random values are required. Get a random
--- value using 'uniform' or 'uniformR':
+-- Hold onto this generator and use it wherever random values are
+-- required (creating a new generator is expensive compared to
+-- generating a random number, so you don't want to throw them
+-- away). Get a random value using 'uniform' or 'uniformR':
 --
 -- @
 --   v <- uniform gen
     (
     -- * Gen: Pseudo-Random Number Generators
       Gen
-    , GenIO
-    , GenST
     , create
     , initialize
     , withSystemRandom
 
+    -- ** Type helpers
+    -- $typehelp
+    , GenIO
+    , GenST
+    , asGenIO
+    , asGenST
+
     -- * Variates: uniformly distributed values
     , Variate(..)
     , uniformVector
 -- | State of the pseudo-random number generator.
 newtype Gen s = Gen (M.MVector s Word32)
 
--- | A shorter name for PRNG state in the IO monad.
+-- | A shorter name for PRNG state in the 'IO' monad.
 type GenIO = Gen (PrimState IO)
 
--- | A shorter name for PRNG state in the ST monad.
+-- | A shorter name for PRNG state in the 'ST' monad.
 type GenST s = Gen (PrimState (ST s))
 
+-- | Constrain the type of an action to run in the 'IO' monad.
+asGenIO :: (GenIO -> IO a) -> (GenIO -> IO a)
+asGenIO = id
+
+-- | Constrain the type of an action to run in the 'ST' monad.
+asGenST :: (GenST s -> ST s a) -> (GenST s -> ST s a)
+asGenST = id
+
 ioff, coff :: Int
 ioff = 256
 coff = 257
   let n    = fromIntegral (numerator t) :: Word64
   return [fromIntegral c, fromIntegral n, fromIntegral (n `shiftR` 32)]
 
--- Aquire seed from /dev/urandom
+-- | Acquire seed from /dev/urandom
 acquireSeedSystem :: IO [Word32]
 acquireSeedSystem = do
   let nbytes = 1024
     peekArray (nread `div` 4) buf
   
 -- | Seed a PRNG with data from the system's fast source of
--- pseudo-random numbers (\"\/dev\/urandom\" on Unix-like systems),
+-- pseudo-random numbers (\"@\/dev\/urandom@\" on Unix-like systems),
 -- then run the given action.
 --
--- This is a heavyweight function, intended to be called only
--- occasionally (e.g. once per thread).  You should use the `Gen` it
--- creates to generate many random numbers.
+-- This is a somewhat expensive function, and is intended to be called
+-- only occasionally (e.g. once per thread).  You should use the `Gen`
+-- it creates to generate many random numbers.
 --
 -- /Note/: on Windows, this code does not yet use the native
 -- Cryptographic API as a source of random numbers (it uses the system
 --   (2007). Gaussian random number generators.
 --   /ACM Computing Surveys/ 39(4).
 --   <http://www.cse.cuhk.edu.hk/~phwl/mt/public/archives/papers/grng_acmcs07.pdf>
+
+-- $typehelp
+--
+-- The functions in this package are deliberately written for
+-- flexibility, and will run in both the 'IO' and 'ST' monads.
+--
+-- This can defeat the compiler's ability to infer a principal type in
+-- simple (and common) cases.  For instance, we would like the
+-- following to work cleanly:
+--
+-- > import System.Random.MWC
+-- > import Data.Vector.Unboxed
+-- >
+-- > main = do
+-- >   v <- withSystemRandom $ \gen -> uniformVector gen 20
+-- >   print (v :: Vector Int)
+--
+-- Unfortunately, the compiler cannot tell what monad 'uniformVector'
+-- should execute in.  The \"fix\" of adding explicit type annotations
+-- is not pretty:
+--
+-- > {-# LANGUAGE ScopedTypeVariables #-}
+-- >
+-- > import Control.Monad.ST
+-- >
+-- > main = do
+-- >   vs <- withSystemRandom $
+-- >         \(gen::GenST s) -> uniformVector gen 20 :: ST s (Vector Int)
+-- >   print vs
+--
+-- As a more readable alternative, this library provides 'asGenST' and
+-- 'asGenIO' to constrain the types appropriately.  We can get rid of
+-- the explicit type annotations as follows:
+--
+-- > main = do
+-- >   vs <- withSystemRandom . asGenST $ \gen -> uniformVector gen 20
+-- >   print (vs :: Vector Int)
+--
+-- This is almost as compact as the original code that the compiler
+-- rejected.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.