我喜欢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.