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

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

Модуль >Control.Exception содержит ещё несколько подобных функций. Функция >finally обеспечивает гарантированное выполнение некоторого действия по завершении другого действия. Это всего навсего упрощённый вариант функции >bracket. Вот её сигнатура:

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

В следующем примере текст >"Готово!" печатается в каждом из двух случаев, несмотря на возникновение исключения во втором:

>ghci> print (20 `div` 10) `finally` putStrLn "Готово!"

>2

>Готово!

>ghci> print (2 `div` 0) `finally` putStrLn "Готово!"

>Готово!

>*** Exception: divide by zero

Функция >onException позволяет выполнить заключительное действие только в случае возникновения исключения:

>ghci> print (20 `div` 10) `onException` putStrLn "Ошибка!"

>2

>ghci> print (2 `div` 0) `finally` putStrLn "Ошибка!"

>Ошибка!

>*** Exception: divide by zero

Заметьте, что обе эти функции, в отличие от >try или >catch, не обрабатывают исключения – они лишь гарантируют выполнение указанных действий. Все эти функции нетрудно реализовать вручную, пользуясь лишь >try или >catch. Фактически они устанавливают свой обработчик, перехватывают исключение, выполняют заданные действия, а после этого повторно генерируют то же самое исключение. Тем не менее, если ваша задача соответствует одному из приведённых сценариев, стоит воспользоваться уже существующей функцией.

10

Решение задач в функциональном стиле

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

Вычисление выражений в обратной польской записи

Обычно мы записываем математические выражения в инфиксной нотации, например: >10 – (4 + 3) * 2. Здесь >+, >* и >– представляют собой инфиксные операторы, такие же, как инфиксные функции Haskell (>+, >`elem` и т. д.). Так нам удобнее, потому что мы можем легко разобрать подобную формулу в уме. Но у такой записи есть и негативное свойство: приходится использовать скобки для обозначения приоритета операций.

Обратная польская запись (ОПЗ) является одним из способов записи математических выражений. В ОПЗ операторы записываются не между числами, а после них. Так, вместо 4 + 3 нужно писать 4 3 +. Но как тогда записать выражения, содержащие несколько операторов? Например, как бы мы записали выражение, складывающее 4 и 3, а потом умножающее сумму на 10? Легко: 4 3 + 10 *. Поскольку 4 3 + равно 7, то всё выражение равно 7 10 *, т. е. 70. Поначалу такая запись воспринимается с трудом, но её довольно просто понять и использовать, так как необходимости в скобках нет и произвести вычисление очень легко. Хотя большинство современных калькуляторов используют инфиксную нотацию, некоторые люди до сих пор являются приверженцами калькуляторов, использующих ОПЗ.