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

в список импорта для модуля >System.IO.Error):

>handler :: IOException -> IO ()

>handler e

>   | isDoesNotExistError e =

>      case ioeGetFileName e of

>        Just fileName -> putStrLn $ "Файл " ++ fileName ++

>                                    " не существует!"

>        Nothing -> putStrLn "Файл не существует!"

>   | otherwise = ioError e

>  where fileName = ioeGetFileName e

В охранном выражении, если предикат >isDoesNotExistError вернёт значение >True, мы использовали выражение >case, чтобы вызвать функцию >ioeGetFileName с параметром >e; затем сделали сопоставление с образцом по возвращённому значению с типом >Maybe. Выражение >case часто используется в случаях, когда вам надо сделать сопоставление с образцом, не создавая новую функцию. Посмотрим, как это сработает:

>$ ./linecount dont_exist.txt

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

Вы не обязаны использовать один обработчик для перехвата всех исключений в части кода, работающей с системой ввода-вывода. Вы можете перекрыть только отдельные части кода с помощью функции >catch или перекрывать разные участки кода разными обработчиками, например так:

>main = do

>   action1 `catch` handler1

>   action2 `catch` handler2

>   launchRockets

Функция >action1 использует функцию >handler1 в качестве обработчика, а функция >action2 использует >handler2. Функция >launchRockets не является параметром функции >catch, так что любое сгенерированное в ней исключение обрушит нашу программу, если только эта функция не использует >try или >catch внутри себя для обработки собственных ошибок. Конечно же, >action1, >action2 и >launchRockets – это действия ввода-вывода, которые «склеены» друг с другом блоком >do и, вероятно, определены где-то в другом месте. Это похоже на блоки >try–catch в других языках: вы можете поместить всю вашу программу в один блок >try–catch или защищать отдельные участки программы и перехватывать различные исключения для разных участков.

Вспомогательные функции для работы с исключениями

Ранее в этой главе мы уже познакомились с функциями >bracket и >bracketOnError, которые реализуют наиболее часто используемый сценарий обработки исключений, когда работа с ресурсом состоит из трёх стадий:

• получение ресурса;

• использование ресурса;

• освобождение ресурса.

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