Основные операции ввода - вывода
7.2. Последовательные операции ввода - вывода
Конструктор типа IO является экземпляром класса Monad. Две монадические связывающие функции, методы в классе Monad, используются для составления последовательностей операций ввода - вывода. Функция >> используется там, где результат первой операции не представляет интереса, например, когда он представляет собой (). Операция >>= передает результат первой операции в качестве аргумента второй операции.
(>>=) :: IO a -> (a -> IO b) -> IO b (>>) :: IO a -> IO b -> IO b
main = readFile "input-file" >>= \ s ->
writeFile "output-file" (filter isAscii s) >>
putStr "Фильтрация завершилась успешно\n"похожа на предыдущий пример, использующий interact, но получает свой ввод из "input-file" и записывает свой вывод в "output-file". Перед завершением программы на стандартный вывод распечатывается сообщение.
Нотация do позволяет программировать в более императивном синтаксическом стиле. Слегка более сложной версией предыдущего примера была бы программа:
main = do
putStr "Файл ввода: "
ifile <- getLine
putStr "Файл вывода: "
ofile <- getLine
s <- readFile ifile
writeFile ofile (filter isAscii s)
putStr "Фильтрация завершилась успешно\n"Функция return используется для определения результата операции ввода - вывода. Например, getLine определена в терминах getChar, используя return для определения результата:
getLine :: IO String
getLine = do c <- getChar
if c == '\n' then return ""
else do s <- getLine
return (c:s)7.3. Обработка исключений в монаде ввода - вывода
Монада ввода - вывода включает простую систему обработки исключений. Любая операция ввода - вывода может вызвать исключение вместо возвращения результата.
Исключения в монаде ввода - вывода представлены значениями типа IOError. Это абстрактный тип: его конструкторы скрыты от пользователя. Библиотека IO определяет функции, которые конструируют и изучают значения IOError . Единственной функцией Prelude, которая создает значение IOError, является userError. Пользовательские значения ошибок включают строку с описанием ошибки.
userError :: String -> IOError
Исключения вызываются и отлавливаются с помощью следующих функций:
ioError :: IOError -> IO a catch :: IO a -> (IOError -> IO a) -> IO a
Функция ioError вызывает исключение; функция catch устанавливает обработчик, который получает любое исключение, вызванное действием, защищенным catch. Исключение отлавливается самым последним обработчиком, установленным catch. Эти обработчики не действуют выборочно: они отлавливают все исключения.
Распространение исключения нужно явно обеспечить в обработчике путем повторного вызова любого нежелательного исключения. Например, в
f = catch g (\e -> if IO.isEOFError e then return [] else ioError e)
функция f возвращает [], когда в g возникает исключение конца файла, иначе исключение передается следующему внешнему обработчику. Функция isEOFError является частью библиотеки IO.
Когда исключение передается за пределы главной программы, система Haskell выводит связанное с ним значение IOError и выходит из программы.
Метод fail экземпляра IO класса Monad (раздел "6.3.6" ) вызывает userError так:
instance Monad IO where
...bindings for return, (>>=), (>>)
fail s = ioError (userError s)Исключения, вызванные функциями ввода - вывода в Prelude, описаны в лекции "21" .