Изучай Haskell во имя добра! (Липовача) - страница 146

>ghci> randomR (1,6) (mkStdGen 359353)

>(6,1494289578 40692)

>ghci> randomR (1,6) (mkStdGen 35935335)

>(3,1250031057 40692)

Также существует функция >randomRs, которая возвращает поток случайных значений в заданном нами диапазоне. Смотрим:

>ghci> take 10 $ randomRs ('a','z') (mkStdGen 3) :: [Char]

>"ndkxbvmomg"

Неплохо, выглядит как сверхсекретный пароль или что-то в этом духе!

Случайность и ввод-вывод

Вы, должно быть, спрашиваете себя: а какое отношение имеет эта часть главы к системе ввода-вывода? Пока ещё мы не сделали ничего, что имело бы отношение к вводу-выводу! До сих пор мы создавали генераторы случайных чисел вручную, основывая их на некотором целочисленном значении. Проблема в том, что если делать так в реальных программах, они всегда будут возвращать одинаковые последовательности случайных чисел, а это нас не вполне устраивает. Вот почему модуль >System.Random содержит действие ввода-вывода >getStdGen, тип которого – >IO StdGen. При запуске программа запрашивает у системы хороший генератор случайных чисел и сохраняет его в так называемом глобальном генераторе. Функция >getStdGen передаёт этот глобальный генератор вам, когда вы связываете её с чем-либо.

Вот простая программа, генерирующая случайную строку.

>import System.Random


>main = do

>   gen <– getStdGen

>   putStrLn $ take 20 (randomRs ('a','z') gen)

Теперь проверим:

>$ ./random_string

>pybphhzzhuepknbykxhe


>$ ./random_string

>eiqgcxykivpudlsvvjpg


>$ ./random_string

>nzdceoconysdgcyqjruo


>$ ./random_string

>bakzhnnuzrkgvesqplrx

Но будьте осторожны: если дважды вызвать функцию >getStdGen, система два раза вернёт один и тот же генератор. Если сделать так:

>import System.Random


>main = do

>   gen <– getStdGen

>   putStrLn $ take 20 (randomRs ('a','z') gen)

>   gen2 <– getStdGen

>   putStr $ take 20 (randomRs ('a','z') gen2)

вы получите дважды напечатанную одинаковую строку.

Лучший способ получить две различные строки – использовать действие ввода-вывода >newStdGen, которое разбивает текущий глобальный генератор на два генератора. Действие замещает глобальный генератор одним из результирующих генераторов и возвращает второй генератор в качестве результата.

>import System.Random


>main = do

>   gen <– getStdGen

>   putStrLn $ take 20 (randomRs ('a','z') gen)

>   gen' <– newStdGen

>   putStr $ take 20 (randomRs ('a','z') gen')

Мы не только получаем новый генератор, когда связываем с чем-либо значение, возвращённое функцией >newStdGen, но и заменяем глобальный генератор; так что если мы воспользуемся функцией >getStdGen ещё раз и свяжем его с чем-нибудь, мы получим генератор, отличный от