以下程序正确终止:
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..5000]
main = do
randomInts <- randomList
print $ take 5 randomInts
跑步:
$ runhaskell test.hs
[26156,7258,29057,40002,26339]
然而,给它一个无限列表,程序永远不会终止,并且在编译时,最终会出现堆栈溢出错误!
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..]
main = do
randomInts <- randomList
print $ take 5 randomInts
跑步,
$ ./test
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
我希望程序在getStdRandom
我每次从列表中选择一个项目时都会懒惰地评估,并在这样做 5 次后完成。为什么要评估整个列表?
谢谢。
有没有更好的方法来获得无限的随机数列表?我想将此列表传递给纯函数。
编辑:更多阅读表明该功能
randomList r = do g <- getStdGen
return $ randomRs r g
是我一直在寻找的。
EDIT2:在阅读了 camccann 的回答后,我意识到getStdGen
每次通话都会获得新的种子。相反,最好将此函数用作简单的一次性随机列表生成器:
import System.Random
randomList :: Random a => a -> a -> IO [a]
randomList r g = do s <- newStdGen
return $ randomRs (r,g) s
main = do r <- randomList 0 (50::Int)
print $ take 5 r
但我仍然不明白为什么我的mapM
电话没有终止。显然与随机数无关,但mapM
可能与此有关。
例如,我发现以下内容也不会终止:
randomList = mapM (\_->return 0) [0..]
main = do
randomInts <- randomList
print $ take 50000 randomInts
是什么赋予了?顺便说一句,恕我直言,上述randomInts
功能应该在System.Random
. 能够非常简单地在 IO monad 中生成随机列表并在需要时将其传递给纯函数非常方便,我不明白为什么这不应该出现在标准库中。