2

我想在 monadGen (ST {..}之外处理/存储随机生成器()ST,但我找不到怎么做。

背景

我正在为一些大量使用随机的模拟工作。通过分析,我知道生成随机数需要超过 50% 的处理时间。

为了制作随机数,我使用mwc-randomSFMT
由于速度问题,我主要使用SFMT.
但是,与 相比SFMTmwc-random具有我需要的更丰富的接口(如normalbernoulli、 ..)。

在基准测试和阅读代码之后,我知道这mwc-random并不比SFMTSTmonad 上使用时慢。
SFMTon IO< MWCon ST<< MWCon IO< SFMTon ST
所以,我想在monad上制作和处理MWC随机生成器。ST但是,我不能像其他东西(例如)ST一样从 monad 中取出这个生成器。STSTRef

问题

有什么方法可以安全地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. 我需要定义/重写数据结构还是做其他事情?有没有更聪明的方法?

要点:

  1. 我需要处理一个随机生成器(如Gen (PrimState (ST s)))来重现结果。
    所以,我不想生产临时随机生成器。
  2. 我不想保存/恢复种子。它的开销太大。(保存/恢复种子比生成一个随机数需要 x12~15 倍)
    它比在 IO monad 上使用要慢,所以我不需要在STmonad 上做。
  3. 我不想使用 unsafe* 函数。
4

1 回答 1

1

您不应该尝试在 ST monad 之外操作生成器。由于 的类型runST,试图使用生活在状态线程“内部”“外部”的东西是没有意义的。想象一下,您有以下类型的函数(这是您要编写的函数):

something :: MWC.Gen s -> Int
something gen = runST ... 

为了生成随机数,必须对Gen. 这些计算将在什么时候完成?如果有的话,他们会做多少次?最重要的是 - 如何something生成随机数 - 毕竟它是一个纯函数,因此它必须为相同的输入返回相同的值。

相反,您应该将状态线程化,并runST在最后调用:

something :: MWC.Gen s -> ST s Int 
something = MWC.uniformR (1,100) 

main = mapM_ print $ runST $ do 
  w0 <- initWorld 
  replicateM 100 (something $ randomGen w0)
于 2015-06-05T00:00:12.490 回答