>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
ещё раз и свяжем его с чем-нибудь, мы получим генератор, отличный от