Главная » Haskell » Модуль Exception

0

 содержит описания программных сущностей, предназначенных для работы с исключениями. Отчасти определения в этом модуле дублируют такие же определение из стандартного модуля Prelude. Импорт же модуля осуществляется следующим образом:

import Control.Exception

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

Тип: Exception

Описание: главный тип для представления исключений. Содержит в себе набор конструкторов, каждый из которых отвечает за определённый тип исключений. Каждое исключение, которое  генерируется операционной системой, имеет этот тип, в то время как  некоторые типы исключений в свою очередь могут иметь подтипы, расшифровываемые при помощи специализированного типа данных. Определение:

data  Exception

= ArithException ArithException | ArrayException ArrayException | AssertionFailed String

| AsyncException  AsyncException  | BlockedOnDeadMVar                     | BlockedIndefinitely

| NestedAtomically                        | Deadlock                                          | DynException  Dynamic

| ErrorCall String                      | ExitException ExitCode               | IOException   IOException

| NoMethodError String               | NonTermination                               | PatternMatchFail String

| RecConError String                  | RecSelError   String                  | RecUpdError String

Конструктор  ArithException отвечает за разнообразные исключения, которые могут возникнуть во время выполнения арифметических  операций. Необходимо отметить, что компилятор GHC на текущий момент может обрабатывать только исключение типа DivideByZero  (деление на ноль).

Конструктор  ArrayException отвечает за все исключения, которые связаны с обработкой массивов. Необходимо отметить, что на текущий момент компилятор GHC не поддерживает этот тип исключений.

Исключение типа AssertionFailed бросается функцией assert (см. стр. 209) в случаях, когда условие ложно. Аргумент этого конструктора типа String может использоваться в качестве ссылки на место в программе, где находится вызов функции assert.

Конструктор  AsyncException используется для исключений, которые могут возникнуть в процессе работы многопоточных приложений при взаимодействии потоков между собой. Данный тип исключений детально описывается ниже.

Исключение типа BlockedOnDeadMVar возбуждается  тогда, когда поток управления был заблокирован при помощи функции takeMVar (см. стр. 189) для переменной синхронизации, у которой более нет ссылок (таким образом заблокированный поток никогда не будет деблокирован).

Исключение типа BlockedIndefinitely выкидывается в случае, когда текущий поток управления заблокирован с невозможностью  снять блокировку, поскольку на атомарную транзакцию, при помощи которой он заблокирован, нет больше ссылок.

Исключение типа NestedAtomically происходит тогда, когда во  время исполнения программы было обнаружено, что внутрь атомарной STM-транзакции была произведена попытка внести ещё одну транзакцию. Обычно это происходит во время использования функции unsafePeformIO (см. стр. 421) над атомарными транзакциями.

Исключение типа Deadlock используется тогда, когда  обнаруживается, что в программе не существует исполняющихся потоков управления (программа «зависла»). Это исключение возбуждается только в главном потоке управления.

Исключение типа DynException является динамически типизируемым исключением (подробно описывается ниже).

Исключение типа ErrorCall возбуждается во время вызова функции error (см. стр. 133). Аргумент конструктора типа String является описанием ошибки, которое выводится на экран.

Исключение типа ExitException выкидывается в случае вызова  функций exitWith (см. стр. 484) и exitFailure (см. стр. 485).  Аргумент конструктора является значением, которое передано этим функциям в качестве входного параметра. Необработанное исключение этого типа в главном потоке управления программы приводит к тому, что программа завершается с заданным кодом выхода.

Конструктор IOException  используется для обработки исключений, возникающих в процессе работы функций ввода/вывода. Все такие  исключения генерируются в монаде IO. См. также  описание модуля  System.IO.Error (подраздел 11.7.1.).

Исключение типа NoMethodError возбуждается в случае, если  производится попытка вызвать метод класса, который не определён для типа, у которого вызывается этот метод, а также нет определения такого метода, используемого по умолчанию. Компилятор GHC в этом случае также генерирует предупреждение об отсутствующем определении метода.

Исключение типа NonTermination используется тогда, когда текущий поток управления завис в бесконечном цикле. Это исключение может и не быть сгенерировано в случаях, когда программа не подразумевает окончания своего исполнения.

Исключение типа PatternMatchFail выкидывается в случае неуспещного процесса сопоставления  с образцами. Аргумент конструктора типа String содержит описание исключения, которое включает наименование функции, в которой произошло исключение, а также имя файла и номер строки в списке определений.

Исключение типа RecConError генерируется тогда, когда  производится попытка вычислить значение поля структуры,  для  которого  не было задано начального значения при создании. Аргумент конструктора типа String описывает местоположение кода для создания поля в исходных кодах программы.

Исключение типа RecSelError  генерируется тогда, когда  производится попытка обратиться к полю структуры, которого вообще не существует у структуры. Такая ситуация может происходить в тех случаях, когда в структуре имеется несколько конструкторов, внутри которых определяются разные наборы полей.

Аргумент конструктора типа String описывает местоположение кода для создания поля в исходных кодах программы.

Исключение типа RecUpdError генерируется тогда, когда  производится попытка записать новое значение в поле структуры, которого вообще не существует в структуре. Такая ситуация может происходить в тех случаях, когда в структуре имеется несколько  конструкторов,  внутри которых определяются разные наборы полей. Аргумент конструктора типа String описывает местоположение кода для создания поля в исходных кодах программы.

Алгебраический тип  данных  Exception   имеет определённые  экземпляры для следующих классов: Eq, Show и Typeable.

Тип: IOException

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

Определение:

Тип определён в виде примитива.

Тип IOException имеет экземпляры следующих классов: Eq, Show и Typeable.

Тип: ArithException

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

Определение:

data  ArithException

= Overflow

| Underflow

| LossOfPrecision

| DivideByZero

| Denormal

Наименование  конструкторов  даёт понимание того, для чего  каждый тип арифметического исключения используется. Тип Overflow используется при переполнении во время арифметических операций. Тип Undeflow также используется при переполнении при использовании действительных чисел, когда точность вычислений выходит за разумные рамки. Исключение LossOfPrecision возбуждается также во время вычислений над действительными числами, когда проис-

ходит потеря точности. Само собой разумеется,  что тип DivideByZero  используется при делении на ноль. Наконец, исключение типа Denormal возбуждается при денормализации числа.

Тип ArithException имеет определённые экземпляры для следующих классов: Eq, Ord, Show и Typeable.

Тип: ArrayException

Описание: данный тип исключений генерируется во время работы с массивами.

Определение:

data  ArrayException

= IndexOutOfBounds String

| UndefinedElement  String

Опять же  наименование конструкторов  намекает на способ  использования конкретного исключения. Тип IndexOutOfBounds возбуждается тогда, когда происходит выход за пределы массива. Тип UndefinedElement генерируется, в свою очередь, при отсутствии элемента массива во время попытки обращения к нему.

Тип ArrayException имеет определённые экземпляры для следующих классов: Eq, Ord, Show и Typeable.

Тип: AsyncException

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

Определение:

data  AsyncException

= StackOverflow

| HeapOverflow

| ThreadKilled

Также  наименования конструкторов  этого  типа  намекают на  способ использования. Тип  StackOverflow   генерируется при  переполнении  стека. Тип HeapOverflow возбуждается при  переполнении  кучи.  Наконец, исключение типа ThreadKilled используется, когда останавливается поток управления.

Тип AsyncException имеет определённые экземпляры для следующих классов: Eq, Ord, Show и Typeable.

Список функций для работы с перечисленными алгебраическими типами данных следующий.

Функция: throwIO

Описание: вариант функции throw (см. ниже), который может быть использован в рамках монады IO. Этот вариант должен быть использован в монаде IO, если имеется нужда в гарантировании того, что исключение не затронет порядок исполнения операций ввода/вывода (функция throw не гарантирует этого). Определение:

throwIO  ::  Exception ->  IO  a

Функция определена в виде примитива.

Функция: throw

Описание: генерирует заданное исключение. Исключения могут  быть  сгенерированы в чистом функциональном коде, но отлавливаться они должны только внутри монады IO.

Определение:

throw  ::  Exception  ->  a

Функция определена в виде примитива.

Функция: ioError

Описание: генерирует исключение типа IOError в рамках монады IO.

Определение:

ioError ::  IOError ->  IO  a

Функция определена в виде примитива.

Функция: throwTo

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

Определение:

throwTo  :: ThreadId  ->  Exception ->  IO ()

Функция определена в виде примитива.

Функция: catch

Описание: основная функция для отлова исключений. Она получает  действие, которое необходимо запустить (и в котором может возникнуть исключение), и запускает его. Если в процессе работы действия происходит исключение, для его обработки вызывается обработчик, переданный в функцию catch  вторым аргументом. Результат его работы возвращается в качестве результата функции. Если же исключений не произошло, результатом работы функции будет результат исходного действия.

Определение:

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

Функция определена в виде примитива.

В качестве примера можно привести такой код:

catch  (openFile f  ReadMode)

(\e ->  hPutStr stderr ("Couldn’t  open " ++ f  ++

":  "  ++ show  e))

Для отлова исключений в чистых функциях необходимо пользоваться функцией evaluate (см. стр. 205).

Надо отметить, что из-за того, что в языке Haskell не определён порядок выполнения вычислений (в силу нестрогости языка), невозможно сказать, в каком порядке и какие исключения будут  сгенерированы и отловлены в случае, если существует несколько вариантов развития таких событий. Например, в выражении

error "Error!" + 1  ‘div‘ 0

неизвестно, какое  исключение будет возбуждено первым —  ErrorCall  или ArithException. Функция catch выполняет недетерминированный отлов исключений, поэтому при повторном вызове того же самого выражения результат может быть иной. Но это  не идёт в разрез с принципом детерминизма функций, поскольку результат находится внутри монады IO.

Необходимо отметить, что  в  стандартном модуле Prelude  имеется  одноимённая функция  catch,   которая   работает с  исключениями  ввода/вывода.

При использовании модуля Exception  желательно скрывать функцию из модуля

Prelude, поскольку описываемая функция является более общей.

Функция: catchJust

Описание: вариант функции catch,  который отличается от исходного варианта тем, что первым параметром принимает на вход  предикат, который  используется для выбора тех исключений, которые интересны именно в этом вызове обработчика. Более того, имеется набор предопределённых предикатов: ioErrors, arithExceptions и т. д. Любые исключения, которые не удовлетворяют предикат, пропускаются этой функцией и могут быть отловлены в более ранних вызовах функций catch или catchJust.

Определение:

catchJust :: (Exception ->  Maybe b)  ->  IO a ->  (b  ->  IO  a)  ->  IO a catchJust p a handler = catch  a handler’

where

handler’ e = case p e of

Nothing  -> throw  e Just  b    ->  handler  b

Функция: handle

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

Определение:

handle  :: (Exception ->  IO a)  ->  IO a ->  IO a handle  =   flip catch

Функция: handleJust

Описание: такая же версия функции catchJust, как и вариант handle. Используется в тех же целях.

Определение:

handleJust :: (Exception ->  Maybe b)  ->  (b  ->  IO a)  ->  IO a ->  IO a handleJust p =   flip (catchJust p)

Функция: try

Описание:  ещё один вариант функции catch, который возвращает значение типа

Either:  конструктор Right  используется в случае, если  исключений  не было,

а конструктор Left  используется, как должно быть понятно, в  случаях, если возникло исключение.

Определение:

try :: IO a ->  IO (Either  Exception a)

try a = catch  (a  >>= \v ->  return  (Right v)) (\e ->  return (Left e))

Необходимо отметить, что в стандартном модуле Prelude имеется одноимённая функция try, которая работает с исключениями ввода/вывода. При использовании модуля Exception  желательно скрывать функцию из модуля Prelude, поскольку описываемая функция является  более общей.

Функция: tryJust

Описание: такой же вариант функции catchJust, как и вариант try для функции

catch. Используется для тех же самых целей.

Определение:

tryJust :: (Exception ->  Maybe b)  ->  IO a ->  IO  (Either b a) tryJust p a = do

r  < try  a case  r  of

Right   v  ->  return  (Right v) Left   e  ->  case p e of

Nothing  ->  throw  e

Just  b   ->  return (Left  b)

Функция: evaluate

Описание: заставляет транслятор языка Haskell вычислить значение выражения, определённого первым аргументом (несмотря на возможные исключения). В качестве результата возвращает вычисленное значение, обёрнутое монадой IO. Определение:

evaluate :: a ->  IO a

Функция определена в виде примитива.

Функция: mapException

Описание: проецирует одно исключение на другое.

Определение:

mapException :: (Exception ->  Exception)  ->  a ->  a mapException f v  =  unsafePerformIO  (catch (evaluate v)

(\x ->  throw  (f x)))

Функция: ioErrors

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с вводом/выводом.

Определение:

ioErrors :: Exception ->  Maybe IOError ioErrors  (IOException e)  = Just  e ioErrors _                            =  Nothing

Функция: arithExceptions

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с арифметическими операциями.

Определение:

arithExceptions :: Exception ->  Maybe  ArithException arithExceptions  (ArithException e)  = Just  e arithExceptions _                                  =  Nothing

Функция: errorCalls

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с вызовом функции error.

Определение:

errorCalls :: Exception ->  Maybe String errorCalls  (ErrorCall e)  = Just  e errorCalls _                        =  Nothing

Функция: assertions

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с вызовом функции assert.

Определение:

assertions :: Exception ->  Maybe  String assertions  (AssertionFailed e)  = Just  e assertions _                                    =  Nothing

Функция: dynExceptions

Описание:   предопределённый предикат   для   использования  в    функциях catchJust, handleJust и tryJust. Определяет набор исключений, которые могут быть назначены динамически.

Определение:

dynExceptions   :: Exception ->  Maybe  Dynamic dynExceptions   (DynException  e)  = Just  e dynExceptions   _                              =  Nothing

Функция: asyncExceptions

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с многопоточностью и работой потоков друг с другом.

Определение:

asyncExceptions :: Exception ->  Maybe  AsyncException  asyncExceptions  (AsyncException e)  = Just  e asyncExceptions  _                                  = Nothing

Функция: userErrors

Описание:   предопределённый предикат   для   использования  в    функциях catchJust,  handleJust и tryJust.  Определяет  набор  исключений, связанных с исключениями, которые определены разработчиком программного обеспечения самостоятельно.

Определение:

userErrors :: Exception ->  Maybe String

userErrors  (IOException e)  | isUserError e = Just  (ioeGetErrorString e) userErrors _                                                           =  Nothing

Функция: throwDyn

Описание: генерирует динамическое исключение, в качестве  которого  может быть «выкинуто» произвольное значение, для которого имеется экземпляр клас-

са Typeable. Эта функция определена для того, чтобы иметь  возможность генерирования произвольных исключений при ограничении, которое накладывает тип Exception  — он не может быть расширен.

Определение:

throwDyn :: Typeable  exception =>  exception ->  b

throwDyn exception = throw  (DynException   (toDyn  exception))

Функция: throwDynTo

Описание: вариант функции  throwDyn, который  имеет те же  свойства, что и функция throwTo (см. стр. 202). Исключение  бросается  в заданном потоке. Данная функция определена только в поставке компилятора GHC.

Определение:

throwDynTo :: Typeable  exception => ThreadId  ->  exception ->  IO ()

Функция определена в виде примитива.

Функция: catchDyn

Описание: отлавливает динамическое исключение заданного типа. Все остальные динамические исключения перегенерируются.

Определение:

catchDyn  :: Typeable  exception => IO a ->  (exception ->  IO  a)  ->  IO a catchDyn  m   k  = catchException m   handle

where

handle  ex = case ex of

(DynException   dyn)  ->  case fromDynamic dyn of

Just  exception  ->  k  exception Nothing                 ->  throw  ex

_                                  ->  throw  ex

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

Функция: block

Описание: эта функция позволяет заблокировать текущий поток таким образом, чтобы он не воспринимал исключений, генерируемых извне, до тех пор, пока текущий поток не будет деблокирован. Любое внешнее исключение не генерирует-

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

Определение:

block   :: IO a  ->  IO a

Функция определена в виде примитива.

Функция: unblock

Описание: функция, обратная по действию функции block. Деблокирует текущий поток так,  что он продолжает воспринимать  исключения, генерируемые извне.

Определение:

unblock  :: IO a  ->  IO a

Функция определена в виде примитива.

Функция: assert

Описание: аналог оператора if, который возвращает значение второго аргумента, если первый аргумент равен True. Если первый аргумент равен FalsE, генерируется исключение типа AssertionFailed с пустой строкой в качестве аргумента. Служебными средствами трансляторов языка Haskell вместо пустой строки подставляются наименование  файла с исходными кодами  и номер строки. Эта функция используется для отладки.

Определение:

assert :: Bool  ->  a ->  a assert  True   x  = x

assert False  _ = throw  (AssertionFailed "")

Функция: bracket

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

Определение:

bracket :: IO a ->  (a  ->  IO b)  ->  (a  ->  IO  c) ->  IO c bracket before   after thing =  block   (do  a < before

r  < catch

(unblock  (thing  a)) (\e  ->  do  after  a

throw  e)

after  a return  r)

Типовым примером использования этой функции является:

bracket

(openFile  "filename"  ReadMode) (hClose)

(\handle ->  do { … })

Функция: bracket-

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

bracket_ :: IO a ->  IO b ->  IO c  ->  IO c

bracket_ before   after thing = bracket before   (const after)  (const thing)

Функция: bracketOnError

Описание: подобна функции bracket, но просто выполняет заключительные действия, не возвращая результата обработки исключения.

Определение:

bracketOnError :: IO a ->  (a  ->  IO b)  ->  (a  ->  IO  c) ->  IO c bracketOnError before   after thing =  block   (do  a < before

catch

(unblock  (thing  a)) (\e  ->  do  after  a

throw  e))

Функция: finally

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

Определение:

finally :: IO a ->  IO b ->  IO a

a ‘finally‘ sequel  = block   (do  r  < catch (unblock  a)

(\e ->  do  sequel throw  e)

sequel return  r)

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

По теме:

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