2011-04-19 54 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