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

Посмотрим на модуль >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)