Выбрать главу

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

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

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

randoms

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

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

randomRIO

:: (a, a) -> IO a

randomIO

:: IO a

Эти функции выполняют тоже, что и основные функции класса, но им не нужен генератор случайных

чисел, они создают его с помощью функции getStdRandom. Экземпляры Random определены для Bool, Char,

Double, Float, Int и Integer. Например так мы можем подбросить кости десять раз:

134 | Глава 8: IO

Prelude System.Random> fmap (take 10 . randomRs (1, 6)) getStdGen

[5,6,5,5,6,4,6,4,4,4]

Prelude System.Random> fmap (take 10 . randomRs (1, 6)) getStdGen

[5,6,5,5,6,4,6,4,4,4]

Обратите внимание на то, что функция getStdGen не обновляет генератор случайных чисел. Мы запра-

шиваем глобальное состояние. Поэтому, дважды подбросив кубик, мы получили одни и те же результаты.

Генератор будет обновляться, если воспользоваться функцией newStdGen:

Prelude System.Random> fmap (take 10 . randomRs (1, 6)) newStdGen

[1,1,5,6,5,2,5,5,5,3]

Prelude System.Random> fmap (take 10 . randomRs (1, 6)) newStdGen

[5,4,6,5,5,5,1,5,5,2]

Создадим случайные слова из пяти букв:

Prelude System.Random> fmap (take 5 . randomRs (’a’, ’z’)) newStdGen

”maclg”

Prelude System.Random> fmap (take 5 . randomRs (’a’, ’z’)) newStdGen

”nfjoa”

Цитатник

Напишем небольшую программу, которая будет выводить на экран в случайном порядке цитаты. Цитаты

хранятся в виде списка пар (автор, высказывание). Сначала мы генерируем случайное число в диапазоне

длины списка, затем выбираем цитату под этим номером и выводим её на экран.

module Main where

import Control.Applicative

import System.Random

main =

format . (quotes !! ) <$> randomRIO (0, length quotes - 1)

>>= putStrLn

format (a, b) = b

++ space ++ a ++ space

where space = ”\n\n”

quotes = [

(”Бьёрн Страуструп”,

”Есть лишь два вида языков программирования: те, \

\ на которые вечно жалуются, и те, которые никогда \

\ не используются.”),

(”Мохатма Ганди”, ”Ты должен быть теми изменениями, которые\

\ ты хочешь видеть вокруг.”),

(”Сократ”, ”Я знаю лишь то, что ничего не знаю.”),

(”Китайская народная мудрость”, ”Сохранив спокойствие в минуту\

\ гнева, вы можете избежать сотни дней сожалений”),

(”Жан Батист Мольер”, ”Медленно растущие деревья приносят лучшие плоды”),

(”Антуан де Сент-Экзюпери”, ”Жить это значит медленно рождаться”),

(”Альберт Эйнштейн”, ”Фантазия важнее знания.”),

(”Тони Хоар”, ”Внутри любой большой программы всегда есть\

\ маленькая, что рвётся на свободу”),

(”Пифагор”, ”Не гоняйся за счастьем, оно всегда находится в тебе самом”),

(”Лао Цзы”, ”Путешествие в тысячу ли начинается с одного шага”)]

Функция format приводит цитату к виду приятному для чтения. Попробуем программу в интерпретаторе:

Prelude> :! ghc --make Quote -o hi

[1 of 1] Compiling Main

( Quote. hs, Quote. o )

Linking hi ...

Prelude> :! ./hi

Путешествие в тысячу ли начинается с одного шага

Лао Цзы

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

Prelude> :! ./hi

Не гоняйся за счастьем, оно всегда находится в тебе самом

Пифагор

Исключения

Мы уже знаем несколько типов, с помощью которых функции могут сказать, что что-то случилось не

так. Это типы Maybe и Either. Если функции не удалось вычислить значение она возвращает специальное

значение Nothing или Left reason, по которому следующая функция может опознать ошибку и предпринять

какие-нибудь действия. Так обрабатываются ошибки в чистых функциях. В этом разделе мы узнаем о том,

как обрабатываются ошибки, которые происходят при взаимодействии с внешним миром, ошибки, которые

происходят внутри типа IO.

Ошибки функций с побочными эффектами обрабатываются с помощью специальной функции catch, она

определена в Prelude:

catch :: IO a -> (IOError -> IO a) -> IO a

Эта функция принимает значение, которое содержит побочные эффекты и функцию, которая обрабаты-

вает исключительные ситуации. К примеру если мы попытаемся прочитать данные из файла, к которому у