Главная » Haskell » Обработка исключений

0

Во время работы с операциями ввода/вывода очень часто происходят ситуации, когда происходят ошибочные ситуации.  Неправильный ввод с клавиатуры, невозможность открытия файла  в силу его отсутствия, невозможность записи в файл в силу отсутствия прав на эту операцию   — это далеко не полный список ситуаций, которые могут привести к ошибкам, которые, в свою очередь, могут остановить программу. В обычных языках программирования в целях обработки подобных ошибочных ситуаций был разработан механизм возбуждения и дальнейшего  отлова так называемых исключений. Так,  функция, в которой произошла ошибка, обрамляет её в некоторый объект, называемый исключением, а потом передает его в обслуживающий модуль. В этом случае программист может самостоятельно отловить исключение и обработать его, а может положиться на операционную систему, у  которой  имеются стандартные  средства для обработки исключений (но в этом варианте придётся смириться с тем, что во многих случаях программа будет остановлена).

Такие же ошибочные ситуации могут возникнуть и внутри действий IO в языке  Haskell. Для этих целей используется  абсолютно такой же  механизм, как и в высокоуровневых императивных языках программирования. Однако если в таких языках имеется специальный синтаксис для описания блоков программного текста, которые предназначены для отлова исключений, то в языке Haskell используется обычный механизм  — использование функций.

Дело в том, что любая ошибка ввода/вывода, которая может возникнуть внутри системы ввода/вывода, имеет тип IOError, а обработчик исключительной ситуации обязан иметь тип IOError ->  IO a. Для связывания обработчика с кодом, в котором возможно возникновение ошибочной ситуации, имеется специальная функция catch, имеющая тип

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

По сигнатуре этой функции видно, что её аргументами являются некоторое действие (первый аргумент, который  может представлять  собой и список действий, оформленный при помощи ключевого слова do) и обработчик исключений (второй аргумент). Возвращает функция результат выполнения некоторых действий, причём эти действия выбираются по простой логике. Если действие, описанное в  первом аргументе, выполнено успешно без возбуждения исключения, то просто возвращается результат этого действия. Если же в процессе выполнения действия возникла ошибка, то она передается обработчику исключений в качестве операнда типа IOError, после чего выполняется сам обработчик. Этот обработчик также выполняет некоторое действие, результат которого возвращается в качестве окончательного результата функции catch.

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

getChar’ :: IO Char

getChar’ = catch  getChar  eofHandler where

eofHandler e = if  (isEofError  e) then  return  ’\n’ else  ioError  e

getString’ :: IO String

getString’ = catch  getString’’ (\e ->  return ("Error: " ++  show e)) where

getString’’  =  do c  < getChar’ if  (c  ==  ’\n’)

then  return  "" else  do

cs  < getString’ return  (c:cs)

На примере определения этих функций видно, что можно использовать вложенные друг в друга обработчики ошибок. В функции getChar’ отлавливается ошибка, которая возникает при обнаружении символа конца файла. Если ошибка другая, то при помощи функции ioError она отправляется дальше и ловится  обработчиком, который  «сидит» в функции getString’.  Для  определённо-

сти в языке Haskell предусмотрен обработчик исключений по умолчанию, который находится на самом верхнем уровне вложенности. Если ошибка не поймана ни одним обработчиком, который написан в программе, то её ловит обработчик по умолчанию, который выводит на экран сообщение об ошибке и останавливает программу.

Более подробно система ввода/вывода  языка Haskell описывается в части II.

этого справочника при детальном описании модуля IO и некоторых других.

Источник: Душкин Р. В., Справочник по языку Haskell. М.: ДМК Пресс, 2008. 544 с., ил.

По теме:

  • Комментарии