2011-04-19 51 views
2

我有一些奇怪的evalRandIO性能问题。这里是有问题的代码:奇怪的表现与evalRandIO

import Control.Monad.Random 

inf :: (RandomGen g, Random a) => Rand g [a] 
inf = sequence $ repeat $ getRandom 

many :: (RandomGen g, Random a) => Int -> Rand g [a] 
many n = sequence $ replicate n $ getRandom 

main = do 
    m <- evalRandIO $ many 1000000 :: IO [Bool] 
    i <- evalRandIO $ inf :: IO [Bool] 
    putStrLn $ show $ take 5 m 
    putStrLn $ show $ take 5 i 

这段代码将打印5个随机布尔变量,然后溢出堆栈。但是,如果我注释掉evalRandIO声明,如下所示:

main = do 
    --m <- evalRandIO $ many 1000000 :: IO [Bool] 
    i <- evalRandIO $ inf :: IO [Bool] 
    --putStrLn $ show $ take 5 m 
    putStrLn $ show $ take 5 i 

代码运行良好。发生什么事?

我ghci的输出:

strontium:movie andrew$ ghci rtest.hs 
GHCi, version 6.12.3: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Loading package ffi-1.0 ... linking ... done. 
Ok, modules loaded: Main. 
Prelude Main> main 
Loading package syb-0.1.0.2 ... linking ... done. 
Loading package base-3.0.3.2 ... linking ... done. 
Loading package mtl-1.1.0.2 ... linking ... done. 
Loading package old-locale-1.0.0.2 ... linking ... done. 
Loading package time-1.1.4 ... linking ... done. 
Loading package random-1.0.0.3 ... linking ... done. 
Loading package MonadRandom-0.1.6 ... linking ... done. 
[True,True,True,True,True] 
[^CInterrupted. 
+0

好的,你打断了跑步。只是为了踢,你可以让它运行,直到它本身(如果它曾经)? – ShiDoiSi 2011-04-19 11:22:25

+0

该计划正在无限期地进食记忆。 – nitromaster101 2011-04-19 14:14:53

回答

3

答案比看起来更简单。当你写:

m <- evalRandIO $ many 1000000 :: IO [Bool] 

evalRandIO的下一次调用将需要评估1000000操作后的种子值。现在需要很多堆栈空间。

因此,当调用inf时,首先必须评估当前的种子值,然后继续进行自己的计算。如果在运行之前INF改变种子你的程序将立即完成:你newStdGen使用当前种子值,所以你必须

import Control.Monad.Random 

inf :: (RandomGen g, Random a) => Rand g [a] 
inf = sequence $ repeat $ getRandom 

many :: (RandomGen g, Random a) => Int -> Rand g [a] 
many n = sequence $ replicate n $ getRandom 

main = do 
    newGen' <- newStdGen 
    m <- evalRandIO $ many 1000000 :: IO [Bool] 
    setStdGen newGen' 
    i <- evalRandIO $ inf :: IO [Bool] 
    putStrLn $ show $ take 5 m 
    putStrLn $ show $ take 5 i 

注意之前呼吁“多”运行

+0

是的,我在想,如果这是同样的问题,在http://stackoverflow.com/questions/3358913/is-mapm-in-haskell-strict-why-does-this-program-get-a-stack-溢出。 – ShiDoiSi 2011-04-19 11:44:47

+0

但这并不能解释堆栈溢出。当然,重复播种应该使用恒定的堆栈空间。我想知道是否有泄漏的地方,但我不能使分析足够详细。 – ShiDoiSi 2011-04-19 14:27:10

0

无法复制在MacOS X 10.6.4:

botanix:~ stolz$ ghci rand.hs 
GHCi, version 6.12.3: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer-gmp ... linking ... done. 
Loading package base ... linking ... done. 
Loading package ffi-1.0 ... linking ... done. 
[1 of 1] Compiling Main    (rand.hs, interpreted) 
Ok, modules loaded: Main. 
*Main> main 
Loading package old-locale-1.0.0.2 ... linking ... done. 
Loading package time-1.1.4 ... linking ... done. 
Loading package random-1.0.0.2 ... linking ... done. 
Loading package transformers-0.2.2.0 ... linking ... done. 
Loading package mtl-2.0.1.0 ... linking ... done. 
Loading package MonadRandom-0.1.6 ... linking ... done. 
[True,False,False,True,True] 
[False,True,False,True,False] 

更新:D'哦,在编译时的表现不同,所以我吃我字:

botanix:~ stolz$ ./a.out 
[False,True,True,False,True] 
Stack space overflow: current size 8388608 bytes. 
+0

我已经在ghci和ghc版本6.12.3中试过了。我使用OS X 10.6。 – nitromaster101 2011-04-19 10:33:25

+0

嗯,这里是10.6.4。那些库的版本呢?你可能会发布ghci-run的完整输出吗? – ShiDoiSi 2011-04-19 10:40:15

+0

我的结果与nitromaster101,GHC 7.0.2,Linux相同。 – Tener 2011-04-19 11:23:14