{-# LANGUAGE BangPatterns, CPP, DeriveDataTypeable, FlexibleContexts,
MagicHash, Rank2Types, ScopedTypeVariables, TypeFamilies, UnboxedTuples #-}-- |-- Module : System.Random.MWC-- Copyright : (c) 2009-2012 Bryan O'Sullivan-- License : BSD3---- Maintainer : bos@serpentine.com-- Stability : experimental-- Portability : portable---- Pseudo-random number generation. This module contains code for-- generating high quality random numbers that follow a uniform-- distribution.---- For non-uniform distributions, see the-- 'System.Random.MWC.Distributions' module.---- The uniform PRNG uses Marsaglia's MWC256 (also known as MWC8222)-- multiply-with-carry generator, which has a period of 2^8222 and-- fares well in tests of randomness. It is also extremely fast,-- between 2 and 3 times faster than the Mersenne Twister.---- The generator state is stored in the 'Gen' data type. It can be-- created in several ways:---- 1. Using the 'withSystemRandom' call, which creates a random state.---- 2. Supply your own seed to 'initialize' function.---- 3. Finally, 'create' makes a generator from a fixed seed.-- Generators created in this way aren't really random.---- For repeatability, the state of the generator can be snapshotted-- and replayed using the 'save' and 'restore' functions.---- The simplest use is to generate a vector of uniformly distributed values:---- @-- vs <- withSystemRandom . asGenST $ \gen -> uniformVector gen 100-- @---- 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.---- @-- gen <- create-- @---- 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-- @---- @-- v <- uniformR (1, 52) gen-- @moduleSystem.Random.MWC(-- * Gen: Pseudo-Random Number GeneratorsGen,create,initialize,withSystemRandom-- ** Type helpers-- $typehelp,GenIO,GenST,asGenIO,asGenST-- * Variates: uniformly distributed values,Variate(..),uniformVector-- * Seed: state management,Seed,fromSeed,toSeed,save,restore-- * References-- $references)where#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)#include "MachDeps.h"#endifimportControl.Monad(ap,liftM,unless)importControl.Monad.Primitive(PrimMonad,PrimState,unsafePrimToIO)importControl.Monad.ST(ST)importData.Bits(Bits,(.&.),(.|.),shiftL,shiftR,xor)importData.Int(Int8,Int16,Int32,Int64)importData.IORef(atomicModifyIORef,newIORef)importData.Ratio((%),numerator)importData.Time.Clock.POSIX(getPOSIXTime)importData.Typeable(Typeable)importData.Vector.Generic(Vector)importData.Word(Word,Word8,Word16,Word32,Word64)importForeign.Marshal.Alloc(allocaBytes)importForeign.Marshal.Array(peekArray)importqualifiedData.Vector.GenericasGimportqualifiedData.Vector.UnboxedasIimportqualifiedData.Vector.Unboxed.MutableasMimportSystem.CPUTime(cpuTimePrecision,getCPUTime)importSystem.IO(IOMode(..),hGetBuf,hPutStrLn,stderr,withBinaryFile)importSystem.IO.Unsafe(unsafePerformIO)importqualifiedControl.ExceptionasE-- | The class of types for which we can generate uniformly-- distributed random variates.---- The uniform PRNG uses Marsaglia's MWC256 (also known as MWC8222)-- multiply-with-carry generator, which has a period of 2^8222 and-- fares well in tests of randomness. It is also extremely fast,-- between 2 and 3 times faster than the Mersenne Twister.---- /Note/: Marsaglia's PRNG is not known to be cryptographically-- secure, so you should not use it for cryptographic operations.classVariateawhere-- | Generate a single uniformly distributed random variate. The-- range of values produced varies by type:---- * For fixed-width integral types, the type's entire range is-- used.---- * For floating point numbers, the range (0,1] is used. Zero is-- explicitly excluded, to allow variates to be used in-- statistical calculations that require non-zero values-- (e.g. uses of the 'log' function).---- To generate a 'Float' variate with a range of [0,1), subtract-- 2**(-33). To do the same with 'Double' variates, subtract-- 2**(-53).uniform::(PrimMonadm)=>Gen(PrimStatem)->ma-- | Generate single uniformly distributed random variable in a-- given range.---- * For integral types inclusive range is used.---- * For floating point numbers range (a,b] is used if one ignores-- rounding errors.uniformR::(PrimMonadm)=>(a,a)->Gen(PrimStatem)->mainstanceVariateInt8whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateInt16whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateInt32whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateInt64whereuniform=uniform2wordsTo64BituniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateWord8whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateWord16whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateWord32whereuniform=uniform1fromIntegraluniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateWord64whereuniform=uniform2wordsTo64BituniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateBoolwhereuniform=uniform1wordToBooluniformR(False,True)g=uniformguniformR(False,False)_=returnFalseuniformR(True,True)_=returnTrueuniformR(True,False)g=uniformg{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateFloatwhereuniform=uniform1wordToFloatuniformR(x1,x2)=uniform1(\w->x1+(x2-x1)*wordToFloatw){-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateDoublewhereuniform=uniform2wordsToDoubleuniformR(x1,x2)=uniform2(\w1w2->x1+(x2-x1)*wordsToDoublew1w2){-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateIntwhere#if WORD_SIZE_IN_BITS < 64uniform=uniform1fromIntegral#elseuniform=uniform2wordsTo64Bit#endifuniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}instanceVariateWordwhere#if WORD_SIZE_IN_BITS < 64uniform=uniform1fromIntegral#elseuniform=uniform2wordsTo64Bit#endifuniformRab=uniformRangeab{-# INLINE uniform #-}{-# INLINE uniformR #-}{-
instance Variate Integer where
uniform g = do
u <- uniform g
return $! fromIntegral (u :: Int)
{-# INLINE uniform #-}
-}instance(Variatea,Variateb)=>Variate(a,b)whereuniformg=(,)`liftM`uniformg`ap`uniformguniformR((x1,y1),(x2,y2))g=(,)`liftM`uniformR(x1,x2)g`ap`uniformR(y1,y2)g{-# INLINE uniform #-}{-# INLINE uniformR #-}instance(Variatea,Variateb,Variatec)=>Variate(a,b,c)whereuniformg=(,,)`liftM`uniformg`ap`uniformg`ap`uniformguniformR((x1,y1,z1),(x2,y2,z2))g=(,,)`liftM`uniformR(x1,x2)g`ap`uniformR(y1,y2)g`ap`uniformR(z1,z2)g{-# INLINE uniform #-}{-# INLINE uniformR #-}instance(Variatea,Variateb,Variatec,Variated)=>Variate(a,b,c,d)whereuniformg=(,,,)`liftM`uniformg`ap`uniformg`ap`uniformg`ap`uniformguniformR((x1,y1,z1,t1),(x2,y2,z2,t2))g=(,,,)`liftM`uniformR(x1,x2)g`ap`uniformR(y1,y2)g`ap`uniformR(z1,z2)g`ap`uniformR(t1,t2)g{-# INLINE uniform #-}{-# INLINE uniformR #-}wordsTo64Bit::(Integrala)=>Word32->Word32->awordsTo64Bitxy=fromIntegral((fromIntegralx`shiftL`32).|.fromIntegraly::Word64){-# INLINE wordsTo64Bit #-}wordToBool::Word32->BoolwordToBooli=(i.&.1)/=0{-# INLINE wordToBool #-}wordToFloat::Word32->FloatwordToFloatx=(fromIntegrali*m_inv_32)+0.5+m_inv_33wherem_inv_33=1.16415321826934814453125e-10m_inv_32=2.3283064365386962890625e-10i=fromIntegralx::Int32{-# INLINE wordToFloat #-}wordsToDouble::Word32->Word32->DoublewordsToDoublexy=(fromIntegralu*m_inv_32+(0.5+m_inv_53)+fromIntegral(v.&.0xFFFFF)*m_inv_52)wherem_inv_52=2.220446049250313080847263336181640625e-16m_inv_53=1.1102230246251565404236316680908203125e-16m_inv_32=2.3283064365386962890625e-10u=fromIntegralx::Int32v=fromIntegraly::Int32{-# INLINE wordsToDouble #-}-- | State of the pseudo-random number generator.newtypeGens=Gen(M.MVectorsWord32)-- | A shorter name for PRNG state in the 'IO' monad.typeGenIO=Gen(PrimStateIO)-- | A shorter name for PRNG state in the 'ST' monad.typeGenSTs=Gen(PrimState(STs))-- | Constrain the type of an action to run in the 'IO' monad.asGenIO::(GenIO->IOa)->(GenIO->IOa)asGenIO=id-- | Constrain the type of an action to run in the 'ST' monad.asGenST::(GenSTs->STsa)->(GenSTs->STsa)asGenST=idioff,coff::Intioff=256coff=257-- | Create a generator for variates using a fixed seed.create::PrimMonadm=>m(Gen(PrimStatem))create=initializedefaultSeed{-# INLINE create #-}-- | Create a generator for variates using the given seed, of which up-- to 256 elements will be used. For arrays of less than 256-- elements, part of the default seed will be used to finish-- initializing the generator's state.---- Examples:---- > initialize (singleton 42)---- > initialize (toList [4, 8, 15, 16, 23, 42])---- If a seed contains fewer than 256 elements, it is first used-- verbatim, then its elements are 'xor'ed against elements of the-- default seed until 256 elements are reached.---- If a seed contains exactly 258 elements, then the last two elements-- are used to set the generator's initial state. This allows for-- complete generator reproducibility, so that e.g. @gen' == gen@ in-- the following example:---- @gen' <- 'initialize' . 'fromSeed' =<< 'save'@initialize::(PrimMonadm,VectorvWord32)=>vWord32->m(Gen(PrimStatem))initializeseed=doq<-M.unsafeNew258fillqiffini==258thendoM.unsafeWriteqioff$G.unsafeIndexseedioff.&.255M.unsafeWriteqcoff$G.unsafeIndexseedcoffelsedoM.unsafeWriteqioff255M.unsafeWriteqcoff362436return(Genq)wherefillq=go0wheregoi|i==256=return()|otherwise=M.unsafeWriteqis>>go(i+1)wheres|i>=fini=iffini==0thenG.unsafeIndexdefaultSeedielseG.unsafeIndexdefaultSeedi`xor`G.unsafeIndexseed(i`mod`fini)|otherwise=G.unsafeIndexseedifini=G.lengthseed{-# INLINE initialize #-}-- | An immutable snapshot of the state of a 'Gen'.newtypeSeed=Seed{-- | Convert seed into vector.fromSeed::I.VectorWord32}deriving(Eq,Show,Typeable)-- | Convert vector to 'Seed'. It acts similarily to 'initialize' and-- will accept any vector. If you want to pass seed immediately to-- restore you better call initialize directly since following law holds:---- > restore (toSeed v) = initialize vtoSeed::(VectorvWord32)=>vWord32->SeedtoSeedv=Seed$I.create$do{Genq<-initializev;returnq}-- | Save the state of a 'Gen', for later use by 'restore'.save::PrimMonadm=>Gen(PrimStatem)->mSeedsave(Genq)=Seed`liftM`G.freezeq{-# INLINE save #-}-- | Create a new 'Gen' that mirrors the state of a saved 'Seed'.restore::PrimMonadm=>Seed->m(Gen(PrimStatem))restore(Seeds)=Gen`liftM`G.thaws{-# INLINE restore #-}-- Aquire seed from current time. This is horrible fallback for-- Windows system.acquireSeedTime::IO[Word32]acquireSeedTime=doc<-(numerator.(%cpuTimePrecision))`liftM`getCPUTimet<-toRational`liftM`getPOSIXTimeletn=fromIntegral(numeratort)::Word64return[fromIntegralc,fromIntegraln,fromIntegral(n`shiftR`32)]-- | Acquire seed from /dev/urandomacquireSeedSystem::IO[Word32]acquireSeedSystem=doletnbytes=1024random="/dev/urandom"allocaBytesnbytes$\buf->donread<-withBinaryFilerandomReadMode$\h->hGetBufhbufnbytespeekArray(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),-- then run the given action.---- 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-- clock instead). As a result, the sequences it generates may not be-- highly independent.withSystemRandom::PrimMonadm=>(Gen(PrimStatem)->ma)->IOawithSystemRandomact=doseed<-acquireSeedSystem`E.catch`\(_::E.IOException)->doseen<-atomicModifyIORefwarned((,)True)unlessseen$dohPutStrLnstderr("Warning: Couldn't open /dev/urandom")hPutStrLnstderr("Warning: using system clock for seed instead "++"(quality will be lower)")acquireSeedTimeunsafePrimToIO$initialize(I.fromListseed)>>=actwherewarned=unsafePerformIO$newIORefFalse{-# NOINLINE warned #-}-- | Compute the next index into the state pool. This is simply-- addition modulo 256.nextIndex::Integrala=>a->IntnextIndexi=fromIntegraljwherej=fromIntegral(i+1)::Word8{-# INLINE nextIndex #-}aa::Word64aa=1540315826{-# INLINE aa #-}uniformWord32::PrimMonadm=>Gen(PrimStatem)->mWord32uniformWord32(Genq)=doi<-nextIndex`liftM`M.unsafeReadqioffc<-fromIntegral`liftM`M.unsafeReadqcoffqi<-fromIntegral`liftM`M.unsafeReadqilett=aa*qi+cc'=fromIntegral(t`shiftR`32)x=fromIntegralt+c'(#x',c''#)|x<c'=(#x+1,c'+1#)|otherwise=(#x,c'#)M.unsafeWriteqix'M.unsafeWriteqioff(fromIntegrali)M.unsafeWriteqcoff(fromIntegralc'')returnx'{-# INLINE uniformWord32 #-}uniform1::PrimMonadm=>(Word32->a)->Gen(PrimStatem)->mauniform1fgen=doi<-uniformWord32genreturn$!fi{-# INLINE uniform1 #-}uniform2::PrimMonadm=>(Word32->Word32->a)->Gen(PrimStatem)->mauniform2f(Genq)=doi<-nextIndex`liftM`M.unsafeReadqioffletj=nextIndexic<-fromIntegral`liftM`M.unsafeReadqcoffqi<-fromIntegral`liftM`M.unsafeReadqiqj<-fromIntegral`liftM`M.unsafeReadqjlett=aa*qi+cc'=fromIntegral(t`shiftR`32)x=fromIntegralt+c'(#x',c''#)|x<c'=(#x+1,c'+1#)|otherwise=(#x,c'#)u=aa*qj+fromIntegralc''d'=fromIntegral(u`shiftR`32)y=fromIntegralu+d'(#y',d''#)|y<d'=(#y+1,d'+1#)|otherwise=(#y,d'#)M.unsafeWriteqix'M.unsafeWriteqjy'M.unsafeWriteqioff(fromIntegralj)M.unsafeWriteqcoff(fromIntegrald'')return$!fx'y'{-# INLINE uniform2 #-}-- Type family for fixed size integrals. For signed data types it's-- its unsigned couterpart with same size and for unsigned data types-- it's same typetypefamilyUnsigneda::*typeinstanceUnsignedInt8=Word8typeinstanceUnsignedInt16=Word16typeinstanceUnsignedInt32=Word32typeinstanceUnsignedInt64=Word64typeinstanceUnsignedInt=WordtypeinstanceUnsignedWord8=Word8typeinstanceUnsignedWord16=Word16typeinstanceUnsignedWord32=Word32typeinstanceUnsignedWord64=Word64typeinstanceUnsignedWord=Word-- Subtract two numbers under assumption that x>=y and store result in-- unsigned data type of same sizesub::(Integrala,Integral(Unsigneda))=>a->a->Unsignedasubxy=fromIntegralx-fromIntegraly{-# INLINE sub #-}add::(Integrala,Integral(Unsigneda))=>a->Unsigneda->aaddmx=m+fromIntegralx{-# INLINE add #-}-- Generate uniformly distributed value in inclusive range.---- NOTE: This function must be fully applied. Otherwise it won't be-- inlined, which will cause a severe performance loss.---- > uniformR = uniformRange -- won't be inlined-- > uniformR a b = uniformRange a b -- will be inlineduniformRange::(PrimMonadm,Integrala,Boundeda,Variatea,Integral(Unsigneda),Bounded(Unsigneda),Variate(Unsigneda))=>(a,a)->Gen(PrimStatem)->mauniformRange(x1,x2)g|n==0=uniformg-- Abuse overflow in unsigned types|otherwise=loopwhere-- Allow ranges where x2<x1(#i,j#)|x1<x2=(#x1,x2#)|otherwise=(#x2,x1#)n=1+subjibuckets=maxBound`div`nmaxN=buckets*nloop=dox<-uniformgifx<maxNthenreturn$!addi(x`div`buckets)elseloop{-# INLINE uniformRange #-}-- | Generate a vector of pseudo-random variates. This is not-- necessarily faster than invoking 'uniform' repeatedly in a loop,-- but it may be more convenient to use in some situations.uniformVector::(PrimMonadm,Variatea,Vectorva)=>Gen(PrimStatem)->Int->m(va)uniformVectorgenn=G.replicateMn(uniformgen){-# INLINE uniformVector #-}defaultSeed::I.VectorWord32defaultSeed=I.fromList[0x7042e8b3,0x06f7f4c5,0x789ea382,0x6fb15ad8,0x54f7a879,0x0474b184,0xb3f8f692,0x4114ea35,0xb6af0230,0xebb457d2,0x47693630,0x15bc0433,0x2e1e5b18,0xbe91129c,0xcc0815a0,0xb1260436,0xd6f605b1,0xeaadd777,0x8f59f791,0xe7149ed9,0x72d49dd5,0xd68d9ded,0xe2a13153,0x67648eab,0x48d6a1a1,0xa69ab6d7,0x236f34ec,0x4e717a21,0x9d07553d,0x6683a701,0x19004315,0x7b6429c5,0x84964f99,0x982eb292,0x3a8be83e,0xc1df1845,0x3cf7b527,0xb66a7d3f,0xf93f6838,0x736b1c85,0x5f0825c1,0x37e9904b,0x724cd7b3,0xfdcb7a46,0xfdd39f52,0x715506d5,0xbd1b6637,0xadabc0c0,0x219037fc,0x9d71b317,0x3bec717b,0xd4501d20,0xd95ea1c9,0xbe717202,0xa254bd61,0xd78a6c5b,0x043a5b16,0x0f447a25,0xf4862a00,0x48a48b75,0x1e580143,0xd5b6a11b,0x6fb5b0a4,0x5aaf27f9,0x668bcd0e,0x3fdf18fd,0x8fdcec4a,0x5255ce87,0xa1b24dbf,0x3ee4c2e1,0x9087eea2,0xa4131b26,0x694531a5,0xa143d867,0xd9f77c03,0xf0085918,0x1e85071c,0x164d1aba,0xe61abab5,0xb8b0c124,0x84899697,0xea022359,0x0cc7fa0c,0xd6499adf,0x746da638,0xd9e5d200,0xefb3360b,0x9426716a,0xabddf8c2,0xdd1ed9e4,0x17e1d567,0xa9a65000,0x2f37dbc5,0x9a4b8fd5,0xaeb22492,0x0ebe8845,0xd89dd090,0xcfbb88c6,0xb1325561,0x6d811d90,0x03aa86f4,0xbddba397,0x0986b9ed,0x6f4cfc69,0xc02b43bc,0xee916274,0xde7d9659,0x7d3afd93,0xf52a7095,0xf21a009c,0xfd3f795e,0x98cef25b,0x6cb3af61,0x6fa0e310,0x0196d036,0xbc198bca,0x15b0412d,0xde454349,0x5719472b,0x8244ebce,0xee61afc6,0xa60c9cb5,0x1f4d1fd0,0xe4fb3059,0xab9ec0f9,0x8d8b0255,0x4e7430bf,0x3a22aa6b,0x27de22d3,0x60c4b6e6,0x0cf61eb3,0x469a87df,0xa4da1388,0xf650f6aa,0x3db87d68,0xcdb6964c,0xb2649b6c,0x6a880fa9,0x1b0c845b,0xe0af2f28,0xfc1d5da9,0xf64878a6,0x667ca525,0x2114b1ce,0x2d119ae3,0x8d29d3bf,0x1a1b4922,0x3132980e,0xd59e4385,0x4dbd49b8,0x2de0bb05,0xd6c96598,0xb4c527c3,0xb5562afc,0x61eeb602,0x05aa192a,0x7d127e77,0xc719222d,0xde7cf8db,0x2de439b8,0x250b5f1a,0xd7b21053,0xef6c14a1,0x2041f80f,0xc287332e,0xbb1dbfd3,0x783bb979,0x9a2e6327,0x6eb03027,0x0225fa2f,0xa319bc89,0x864112d4,0xfe990445,0xe5e2e07c,0xf7c6acb8,0x1bc92142,0x12e9b40e,0x2979282d,0x05278e70,0xe160ba4c,0xc1de0909,0x458b9bf4,0xbfce9c94,0xa276f72a,0x8441597d,0x67adc2da,0x6162b854,0x7f9b2f4a,0x0d995b6b,0x193b643d,0x399362b3,0x8b653a4b,0x1028d2db,0x2b3df842,0x6eecafaf,0x261667e9,0x9c7e8cda,0x46063eab,0x7ce7a3a1,0xadc899c9,0x017291c4,0x528d1a93,0x9a1ee498,0xbb7d4d43,0x7837f0ed,0x34a230cc,0x614a628d,0xb03f93b8,0xd72e3b08,0x604c98db,0x3cfacb79,0x8b81646a,0xc0f082fa,0xd1f92388,0xe5a91e39,0xf95c756d,0x1177742f,0xf8819323,0x5c060b80,0x96c1cd8f,0x47d7b440,0xbbb84197,0x35f749cc,0x95b0e132,0x8d90ad54,0x5c3f9423,0x4994005b,0xb58f53b9,0x32df7348,0x60f61c29,0x9eae2f32,0x85a3d398,0x3b995dd4,0x94c5e460,0x8e54b9f3,0x87bc6e2a,0x90bbf1ea,0x55d44719,0x2cbbfe6e,0x439d82f0,0x4eb3782d,0xc3f1e669,0x61ff8d9e,0x0909238d,0xef406165,0x09c1d762,0x705d184f,0x188f2cc4,0x9c5aa12a,0xc7a5d70e,0xbc78cb1b,0x1d26ae62,0x23f96ae3,0xd456bf32,0xe4654f55,0x31462bd8]{-# NOINLINE defaultSeed #-}-- $references---- * Marsaglia, G. (2003) Seeds for random number generators.-- /Communications of the ACM/ 46(5):90&#8211;93.-- <http://doi.acm.org/10.1145/769800.769827>---- * Thomas, D.B.; Leong, P.G.W.; Luk, W.; Villasenor, J.D.-- (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.