如何存储ST monad的东西?

时间:2015-06-04 06:44:48

标签: haskell monads st

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

背景

我正在为一些大量使用随机的模拟工作。 通过分析,我知道随机数占据处理时间的50%以上。

要创建随机数,我使用mwc-randomSFMT 由于速度问题,我主要使用SFMT 但是,与SFMTmwc-random相比,我需要更丰富的界面(例如normalbernoulli,..)。

在基准和读取代码之后,我了解mwc-randomSFMT monad上使用时ST并不比SFMT慢。 (IO上的MWC< ST MWC<< IO SFMT< ST {{{{} {MWC 1}})
所以,我想在ST monad上制作和处理ST随机生成器。 但是,我无法将ST monad中的此生成器与其他STRef内容相同(例如ST)。

问题

有没有办法在STRef monad 安全地之外处理/存储这个随机生成器?

我尝试使用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))。 我是否需要定义/重写数据结构或执行其他操作? 有更聪明的方法吗?

点数:

  1. 我需要处理一个随机生成器(如ST)来重现结果 所以,我不想生产ad-hoc随机生成器。
  2. 我不想保存/恢复种子。它的开销太大了。 (保存/恢复种子比生成一个随机数需要x12~15倍)
    它比在IO monad上使用要慢,所以我不需要在 86 Query select * from blacklist where mobile_token = 'b' 86 Query SHOW WARNINGS 86 Query select @@session.tx_read_only 86 Query update mydatabase.blacklist set email=null, iban=null, mobile_token=null, nif=null where blacklist_id=1 86 Query SHOW WARNINGS 86 Query commit 86 Query SET autocommit=1 86 Query SET autocommit=1 86 Query set session transaction read write monad上进行。
  3. 我不想使用不安全的*功能。

1 个答案:

答案 0 :(得分:1)

你不应该试图在ST monad之外操纵发生器。由于runST的类型,试图使用生活内容&#34;内部&#34;国家线程&#34;外部&#34;这是非荒谬的。想象一下,你有一个以下类型的函数(这是你要写的函数):

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)