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

. Если исключение вызвано другими причинами, перевызываем исключение с помощью функции >ioError.

ПРИМЕЧАНИЕ. Функции >try, >catch, >ioError и некоторые другие объявлены одновременно в модулях >System.IO.Error (устаревший вариант) и >Control.Exception (современный вариант), поэтому подключение обоих модулей (например, для использования предикатов исключений ввода-вывода) требует скрывающего или квалифицированного импорта либо же, как в предыдущем примере, явного указания импортируемых функций.

Итак, исключение, произошедшее в действии ввода-вывода >countLines, но не по причине отсутствия файла, будет перехвачено и перевызвано в обработчике:

>$ ./linecount dont_exist.txt

>Файл не существует!

>$ ./linecount norights.txt

>linecount: noaccess.txt: openFile: permission denied (Permission denied)

Существует несколько предикатов, предназначенных для определения вида исключения ввода-вывода:

• >isAlreadyExistsError (файл уже существует);

• >isDoesNotExistError (файл не существует);

• >isAlreadyInUseError (файл уже используется);

• >isFullError (не хватает места на диске);

• >isEOFError (достигнут конец файла);

• >isIllegalOperation (выполнена недопустимая операция);

• >isPermissionError (недостаточно прав доступа).

Пользуясь этими предикатами, можно написать примерно такой обработчик:

>handler :: IOException -> IO ()

>handler e

>   | isDoesNotExistError e = putStrLn "Файл не существует!"

>   | isPermissionError e = putStrLn "Не хватает прав доступа!"

>   | isFullError e = putStrLn "Освободите место на диске!"

>   | isIllegalOperation e = putStrLn "Караул! Спасите!"

>   | otherwise = ioError e

Убедитесь, что вы перевызываете исключение, если оно не подходит под ваши критерии; в противном случае ваша программа иногда будет «падать» молча, что крайне нежелательно.

Модуль >System.IO.Error также экспортирует функции, которые позволяют нам получать атрибуты исключения, например дескриптор файла, вызвавшего исключение, или имя файла. Все эти функции начинаются с префикса >ioe; их полный список вы можете найти в документации. Скажем, мы хотим напечатать имя файла в сообщении об ошибке. Значение >fileName, полученное при помощи функции >getArgs, напечатать нельзя, потому что в обработчик передаётся только значение типа >IOException и он не знает ни о чём другом. Функция зависит только от своих параметров. Но мы можем вызвать функцию >ioeGetFileName, которая по переданному ей исключению возвращает >Maybe FilePath. Функция пытается получить из значения исключения имя файла, если такое возможно. Давайте изменим обработчик так, чтобы он печатал полное имя файла, из-за которого возникло исключение (не забудьте включить функцию