Infinite random sequence loops with randomIO but not with getRandom

时光毁灭记忆、已成空白 提交于 2019-12-23 02:38:33

问题


I'm having difficulty trying to figure out a way to reason about why the following two, seemingly equivalent definitions of an infinite random number sequence (inf and inf') are evaluated completely differently:

import Control.Monad.Random (Rand, evalRandIO, getRandom)
import System.Random        (Random, RandomGen, randomIO)

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

inf' :: (Random a) => IO [a]
inf' = sequence (repeat randomIO)

-- OK
main = do
  i <- evalRandIO inf
  putStrLn $ show $ take 5 (i :: [Int])

-- HANGS
main' = do
  i <- inf'
  putStrLn $ show $ take 5 (i :: [Int])

when called, main' terminates and prints 5 random integers, whereas main loops infinitely — what causes sequence . repeat to be evaluated differently on getRandom than it does on randomIO?


回答1:


Sequencing lists is strict in the IO monad but possibly lazy in the State monad. Rand is just a wrapped StateT, so it can be lazy:

type Rand g = RandT g Identity
newtype RandT g m a = RandT (StateT g m a)

evalRandIO queries the IO random number generator just once at the beginning, then runs the State-ful computation on the acquired StdGen:

evalRandT :: (Monad m) => RandT g m a -> g -> m a
evalRandT (RandT x) g = evalStateT x g

evalRand :: Rand g a -> g -> a
evalRand x g = runIdentity (evalRandT x g)

evalRandIO :: Rand StdGen a -> IO a
evalRandIO x = fmap (evalRand x) newStdGen

In contrast, sequence $ repeat randomIO contains an infinite number of side effecting IO actions, because each randomIO modifies the global random number generator. We can't inspect the return value until all the effects are performed. It's similar to doing sequence $ repeat getLine, which just reads lines repeatedly, and never returns.



来源:https://stackoverflow.com/questions/30527699/infinite-random-sequence-loops-with-randomio-but-not-with-getrandom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!