52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 143

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 143

Давайте посмотрим как это происходит в интерпретаторе:

Типичные задачи IO | 133

Prelude> :m System.Random

Prelude System.Random> let g0 = mkStdGen 0

Prelude System.Random> let (n0, g1) = next g0

Prelude System.Random> let (n1, g2) = next g1

Prelude System.Random> n0

2147482884

Prelude System.Random> n1

2092764894

Мы создали первый генератор, а затем начали получать новые. Для того, чтобы получать новые случайные

числа, нам придётся таскать везде за собой генератор случайных чисел. Мы можем обернуть его в функцию

с состоянием и пользоваться методами классов Functor, Applicative и Monad. Обновление генератора будет

происходить за ширмой, во время применения функций. Но у нас есть и другой путь.

Вместо монады State мы можем воспользоваться монадой IO. Если нам лень определять генератор слу-

чайных чисел, мы можем попросить компьютер определить его за нас. В этом случае мы взаимодействуем с

компьютером, мы запрашиваем глобальное для системы случайное значение, поэтому возвращаемое значе-

ние будет завёрнуто в тип IO. Для этого определены функции:

getStdGen :: IO StdGen

newStdGen :: IO StdGen

Функция getStdGen запрашивает глобальный для системы генератор случайных чисел. Функция

newStdGen не только запрашивает генератор, но также и обновляет его. Мы пользуемся этими функци-

ями так же как и mkStdGen, только теперь мы спрашиваем первый аргумент у компьютера, а не передаём его

вручную. Также есть ещё одна полезная функция:

getStdRandom

:: (StdGen -> (a, StdGen)) -> IO a

Посмотрим, что получится, если передать в неё функцию next:

Prelude System.Random> getStdRandom next

1386438055

Prelude System.Random> getStdRandom next

961860614

И не надо обновлять никаких генераторов. Но вместо одного неудобства мы получили другое. Теперь

значение завёрнуто в оболочку IO.

Генератор StdGen делает случайные числа из диапазона всех целых чисел. Что если мы хотим получить

только числа из некоторого интервала? И как получить случайные значения других типов? Для этого суще-

ствует класс Random. Он является удобной надстройкой над классом RandomGen. Посмотрим на его основные

методы:

class Random a where

randomR :: RandomGen g => (a, a) -> g -> (a, g)

random

:: RandomGen g => g -> (a, g)

Метод randomR принимает диапазон значений, генератор случайных чисел и возвращает случайное число

из указанного диапазона и обновлённый генератор. Метод random является синонимом метода next из класса

RandomGen, только теперь мы можем получать не только целые числа.

Есть и дополнительные методы. Есть методы, которые позволяют генерировать список всех возможных

случайных значений для данного генератора:

randomRs :: RandomGen g => (a, a) -> g -> [a]

randoms

:: RandomGen g => g -> [a]

За счёт лени мы будем получать новые значения по мере необходимости.