我想在 monadGen (ST {..}
之外处理/存储随机生成器()ST
,但我找不到怎么做。
背景
我正在为一些大量使用随机的模拟工作。通过分析,我知道生成随机数需要超过 50% 的处理时间。
为了制作随机数,我使用mwc-random和SFMT。
由于速度问题,我主要使用SFMT
.
但是,与 相比SFMT
,mwc-random
具有我需要的更丰富的接口(如normal
、bernoulli
、 ..)。
在基准测试和阅读代码之后,我知道这mwc-random
并不比SFMT
在ST
monad 上使用时慢。
(SFMT
on IO
< MWC
on ST
<< MWC
on IO
< SFMT
on ST
)
所以,我想在monad上制作和处理MWC
随机生成器。ST
但是,我不能像其他东西(例如)ST
一样从 monad 中取出这个生成器。ST
STRef
问题
有什么方法可以安全地ST
在monad之外处理/存储这个随机生成器?
我试图从许多包/代码STRef
或其他东西中学习,但我无法弄清楚。
例子
我像这样在模拟中使用随机生成器。
import qualified System.Random.MWC as MWC
import GHC.Prim
import Control.Monad
data World = World { randomGen :: MWC.Gen RealWorld }
initWorld = do gen <- MWC.create
return $ World gen
something gen = do num <- MWC.uniformR (1,100) gen :: IO Int
print num
main = do world <- initWorld
replicateM_ 100 $ something (randomGen world)
但是,此代码不起作用。
import qualified System.Random.MWC as MWC
import Control.Monad
import Control.Monad.Primitive
import Control.Monad.ST
data World s = World { randomGen :: MWC.Gen (PrimState (ST s))}
initWorld :: ST s (World s)
initWorld = do gen <- MWC.create
return $ World gen
something gen = do
let num :: Int
num = runST $ do num <- MWC.uniformR (1,100) gen
return num
print num
main = do let world = runST initWorld
replicateM_ 100 $ something (randomGen world)
我想重写此代码以使用something
. 我需要定义/重写数据结构还是做其他事情?有没有更聪明的方法?
要点:
- 我需要处理一个随机生成器(如
Gen (PrimState (ST s))
)来重现结果。
所以,我不想生产临时随机生成器。 - 我不想保存/恢复种子。它的开销太大。(保存/恢复种子比生成一个随机数需要 x12~15 倍)
它比在 IO monad 上使用要慢,所以我不需要在ST
monad 上做。 - 我不想使用 unsafe* 函数。