Посмотрим на модуль >System.Random
. В нём содержатся функции, которые удовлетворят все наши нужды в отношении случайностей! Давайте посмотрим на одну из экспортируемых функций, а именно >random
. Вот её тип:
>random :: (RandomGen g, Random a) => g –> (a, g)
Так! В декларации мы видим несколько новых классов типов. Класс типов >RandomGen
предназначен для типов, которые могут служить источниками случайности. Класс типов >Random
предназначен для типов, которые могут принимать случайные значения. Булевские значения могут быть случайными; это может быть >True
или >False
. Число может принимать огромное количество случайных значений. Может ли функция принимать случайное значение? Не думаю – скорее всего, нет! Если мы попытаемся перевести объявление функции >random
на русский язык, получится что-то вроде «функция принимает генератор случайности (источник случайности), возвращает случайное значение и новый генератор случайности». Зачем она возвращает новый генератор вместе со случайным значением?.. Увидим через минуту.
Чтобы воспользоваться функцией >random
, нам нужно получить один из генераторов случайности. Модуль >System.Random
экспортирует полезный тип >StdGen
, который имеет экземпляр класса >RandomGen
. Мы можем создать значение типа >StdGen
вручную или попросить систему выдать нам генератор, основывающийся на нескольких вроде бы случайных вещах.
Для того чтобы создать генератор вручную, используйте функцию >mkStdGen
. Её тип – >mkStdGen :: Int –> StdGen
. Он принимает целое число и основывается на нём, возвращая нам генератор. Давайте попробуем использовать функции >random
и >mkStdGen
, чтобы получить… сомнительно, что случайное число.
>ghci> random (mkStdGen 100)
>:1:0:
> Ambiguous type variable `a' in the constraint:
> `Random a' arising from a use of `random' at :1:0–20
> Probable fix: add a type signature that fixes these type variable(s)
Что это?… Ах, да, функция >random
может возвращать значения любого типа, который входит в класс типов >Random
, так что мы должны указать языку Haskell, какой тип мы желаем получить в результате. Также не будем забывать, что функция возвращает случайное значение и генератор в паре.
>ghci> random (mkStdGen 100) :: (Int, StdGen)
>(–1352021624,651872571 1655838864)
Ну наконец-то! Число выглядит довольно-таки случайным. Первый компонент кортежа – это случайное число, второй элемент – текстовое представление нового генератора. Что случится, если мы вызовем функцию >random
с тем же генератором снова?
>ghci> random (mkStdGen 100) :: (Int, StdGen)