1

У меня возникли трудности с попыткой выяснить, почему следующие два, казалось бы, эквивалентные определения бесконечной последовательности случайных чисел (inf и inf') оцениваются совершенно по-разному :Бесконечные циклы случайной последовательности с randomIO, но не с getRandom

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]) 

при вызове main' завершаясь и печатает 5 случайных чисел, в то время как main петель бесконечно - то, что вызывает sequence . repeat быть оценены по-разному на getRandom, чем на randomIO?

+0

Вы имеете в виду, что 'main' завершается и' main'' висит? –

+0

@ AndrásKovács да, точно. –

+3

Существует важное различие между ними. 'evalRandIO' использует' IO' для получения начального генератора, генерируя бесконечный список из этого, не требует больше ввода-вывода. 'randomIO' требует вызова' IO' для каждого случайного числа, поэтому он зависает, когда он пытается вернуться в бесконечный список (если вы не используете 'unsaveInterleaveIO'). – cchalmers

ответ

3

Списки секвенирования строги в монаде IO, но, возможно, ленивы в государственной монаде. Rand просто wrapped StateT, так что это может быть ленивым:

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

evalRandIO запрашивает генератор случайных чисел IO только один раз в начале, а затем запускает State -ful вычисления на приобретенную 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 содержит бесконечное количество побочных эффектов IO, поскольку каждый randomIO модифицирует генератор глобальных случайных чисел. Мы не можем проверить возвращаемое значение до тех пор, пока все эффекты не будут выполнены. Это похоже на выполнение sequence $ repeat getLine, который просто читает строки несколько раз и никогда не возвращается.

 Смежные вопросы

  • Нет связанных вопросов^_^