8

I'm working with the packages System.Random.Mersenne.Pure64 and Control.Monad.Mersenne.Random by Don Stewart which are usually blazingly fast, and are supposed to help avoid common errors, like using non-strict state monads.

Nevertheless, I managed to write some code that results in a stack overflow for moderately large vectors.

import qualified Data.Vector.Unboxed as U
import Data.Int
import System.Random.Mersenne.Pure64
import Control.Monad.Mersenne.Random

main = do
    let dim = 1000000
        y = evalRandom (U.replicateM dim getInt64) (pureMT 13) :: U.Vector Int64
    putStr $ (show $ U.head y)

I'm guessing this must be due to laziness in Vector's replicateM implementation, though it's difficult to see since it is implemented using streams.

How might I write code that uses constant stack space to sample large vectors?

4

1 回答 1

6

monad-mersenne-random 没有什么明显的错误(没有看核心一iota),但值得注意的是,使用状态单子时一切正常:

import Control.Monad.State

...

        y      = evalState (U.replicateM dim (state $ \s -> randomInt64 s)) (pureMT 13) :: U.Vector Int64

结果是:

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3
$ ghc so.hs -fforce-recomp
[1 of 2] Compiling Control.Monad.Mersenne.Random ( Control/Monad/Mersenne/Random.hs, Control/Monad/Mersenne/Random.o )
[2 of 2] Compiling Main             ( so.hs, so.o )
Linking so ...
$ ./so
-7188968464842378225

编辑:

查看两个 monad 定义 (StateTRand) 似乎唯一真正的区别在于元组的严格性。所以我尝试使用Control.Monad.State.Strict和啊哈!堆栈溢出返回。所以我猜想埋在 Vector 的replicateM代码中的东西类似于from中foldr使用的东西。这可以解释为什么您不希望序列严格。replicateMbase

于 2013-11-13T08:25:25.683 回答