我喜欢mersenne-random-pure64包.例如,您可以像这样使用它从种子值生成无限懒惰的随机双精度流:
import Data.Word (Word64)
import Data.List (unfoldr)
import System.Random.Mersenne.Pure64
randomStream :: (PureMT -> (a, PureMT)) -> PureMT -> [a]
randomStream rndstep g = unfoldr (Just . rndstep) g
toStream :: Word64 -> [Double]
toStream seed = randomStream randomDouble $ pureMT seed
main = print . take 10 $ toStream 42
Run Code Online (Sandbox Code Playgroud)
使用System.Random(randoms)
你可以使用内置randoms
函数得到一个类似的输出,它更短更通用(感谢ehird指出):
import System.Random (randoms)
import System.Random.Mersenne.Pure64 (pureMT)
main = print . take 10 $ randomdoubles where
randomdoubles :: [Double]
randomdoubles = randoms $ pureMT 42
Run Code Online (Sandbox Code Playgroud)
使它成为MonadRandom的一个实例
在阅读之后,MonadRandom
我很好奇如何将其PureMT
作为一个实例.开箱即用它不起作用,因为PureMT
没有实例化RandomGen
的split
功能.使它工作的方法之一是包裹PureMT
在一个newtype
和编写自定义split
实例的RandomGen
类型类,对其存在一个默认MonadRandom
实例.
import Control.Monad.Random
import System.Random.Mersenne.Pure64
getTenRandomDoubles :: Rand MyPureMT [Double]
getTenRandomDoubles = getRandoms >>= return . take 10
main = print $ evalRand getTenRandomDoubles g
where g = MyPureMT $ pureMT 42
newtype MyPureMT = MyPureMT { unMyPureMT :: PureMT }
myPureMT = MyPureMT . pureMT
instance RandomGen MyPureMT where
next = nextMyPureMT
split = splitMyPureMT
splitMyPureMT :: MyPureMT -> (MyPureMT, MyPureMT)
splitMyPureMT (MyPureMT g) = (myPureMT s, myPureMT s') where
(s',g'') = randomWord64 g'
(s ,g' ) = randomWord64 g
nextMyPureMT (MyPureMT g) = (s, MyPureMT g') where
(s, g') = randomInt g
Run Code Online (Sandbox Code Playgroud)
标准的System.Random有一个纯接口.我会建议在包装它State g
(无论何种发电机摹你使用),以避免线程的状态; 该state
功能使转换功能变得像next
容易进行状态操作:
next :: (RandomGen g) => g -> (Int, g)
state :: (s -> (a, s)) -> State s a
state next :: (RandomGen g) => State g Int
Run Code Online (Sandbox Code Playgroud)
所述MonadRandom包是基于上State g
与发电机的功能预先写好的包装接口; 我觉得它很受欢迎.
请注意,您仍然可以在全局RNG上使用此纯接口运行操作.MonadRandom有evalRandIO用于此目的.
我想你可以写一个(孤儿)RandomGen实例来使用mwc-random.