$ ./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
ещё раз и свяжем его с чем-нибудь, мы получим генератор, отличный от gen
.
Вот маленькая программка, которая заставляет пользователя угадывать загаданное число.
import System.Random
import Control.Monad(when)
main = do
gen <- getStdGen
askForNumber gen
askForNumber :: StdGen -> IO ()
askForNumber gen = do
let (randNumber, newGen) = randomR (1,10) gen :: (Int, StdGen)
putStr "Я задумал число от 1 до 10. Какое? "
numberString <- getLine
when (not $ null numberString) $ do
let number = read numberString
if randNumber == number
then putStrLn "Правильно!"
else putStrLn $ "Извините, но правильный ответ "
++ show randNumber
askForNumber newGen
Здесь мы создаём функцию askForNumber
, принимающую генератор случайных чисел и возвращающую действие ввода-вывода, которое спросит число у пользователя и сообщит ему, угадал ли он. В этой функции мы сначала генерируем случайное число и новый генератор, основываясь на исходном генераторе; случайное число мы называем randNumber
, а новый генератор – newGen
. Допустим, что было сгенерировано число 7. Затем мы предлагаем пользователю угадать, какое число мы задумали. Вызываем функцию getLine
и связываем её результат с идентификатором numberString
. Если пользователь введёт 7
, numberString
будет равно 7
. Далее мы используем функцию when
для того, чтобы проверить, не ввёл ли пользователь пустую строку. Если ввёл, выполняется пустое действие ввода-вывода return()
, которое закончит выполнение программы. Если пользователь ввёл не пустую строку, выполняется действие, состоящее из блока do
. Мы вызываем функцию read
со значением numberString
в качестве параметра, чтобы преобразовать его в число; образец number
становится равным 7
.
ПРИМЕЧАНИЕ. На минуточку!.. Если пользователь введёт что-нибудь, чего функция read
не сможет прочесть (например, "ха-ха"
), наша программа «упадёт» с ужасным сообщением об ошибке. Если вы не хотите, чтобы программа «падала» на некорректном вводе, используйте функцию reads:
она возвращает пустой список, если у функции не получилось считать строку. Если чтение прошло удачно, функция вернёт список из одного элемента, содержащий пару, один компонент которой содержит желаемый элемент; второй компонент хранит остаток строки после считывания первого.