无限随机序列使用randomIO循环,但不使用getRandom [英] Infinite random sequence loops with randomIO but not with getRandom
问题描述
我很难找出一种推理方式来解释为什么以下两个看似等价的无限随机数序列( inf 和<$ c
$ $ p $ import Control.Monad.Random(Rand c> inf'
)完全不同: ,evalRandIO,getRandom)
import System.Random(Random,RandomGen,randomIO)
$ b $ 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])
被调用时, main'
终止并打印5个随机整数,而 main
无限循环 - 导致序列的原因。重复
在 getRandom
上的计算方式不同于
排序列表在IO monad中是严格的,但在状态monad中可能是惰性的。 兰德
只是一个包裹 StateT
,所以可能很懒惰:
type Rand g = RandT g Identity
newtype RandT gma = RandT(StateT gma)
evalRandIO
在一开始就查询IO随机数发生器,然后运行 State
对获得的 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
相比之下, sequence $ repeat randomIO
包含无限数量的副作用,因为每个 randomIO
修改全局随机数生成器。我们无法检查返回值,直到执行所有效果。它类似于执行 sequence $ repeat getLine
,它只是反复读取行,并且永远不会返回。
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
?
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.
这篇关于无限随机序列使用randomIO循环,但不使用getRandom的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!