【发布时间】:2015-06-04 06:44:48
【问题描述】:
我想在ST monad 之外处理/存储随机生成器(Gen (ST {..}),但我找不到怎么做。
背景
我正在做一些大量使用随机的模拟。 通过分析,我知道生成随机数需要超过 50% 的处理时间。
为了生成随机数,我使用mwc-random 和SFMT。
由于速度问题,我主要使用SFMT。
但是,与SFMT、mwc-random 相比,我需要更丰富的接口(如normal、bernoulli、..)。
在基准测试和阅读代码之后,我了解到mwc-random 在ST monad 上使用时不会比SFMT 慢。
(SFMTIOMWCSTMWCIOSFMTST)
所以,我想在ST monad 上制作和处理MWC 随机生成器。
但是,我不能像其他 ST 一样从 ST monad 中取出这个生成器(例如 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 上使用要慢,所以我不需要在STmonad 上做。 - 我不想使用 unsafe* 函数。
【问题讨论】:
-
您不能同时拥有 2 和 3。
save和restore是安全的,因为它们复制了底层向量。不复制任何东西都不会阻止改变一个所谓的不可变值。难道你不能通过在单个 ST 范围或内部 IO 中完成所有(或大部分)工作来避免保存和恢复吗? -
另外,这可能是
unsafeInterleaveST是“净化”增量操作的好选择。