ЗНАЕТЕ ЛИ ВЫ?

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



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

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

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

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

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

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

 
 

Модуль 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. Фактически они устанавлива- ют свой обработчик, перехватывают исключение, выполняют за- данные действия, а после этого повторно генерируют то же самое исключение. Тем не менее, если ваша задача соответствует одному из приведённых сценариев, стоит воспользоваться уже существую- щей функцией.


 

РЕШЕНИЕ ЗАДАЧ

В ФУНКЦИОНАЛЬНОМ СТИЛЕ

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

 

Вычисление выражений

в обратной польской записи

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

Обратная польская запись (ОПЗ) является одним из способов за- писи математических выражений. В ОПЗ операторы записывают- ся не между числами, а после них. Так, вместо 4 + 3 нужно писать 4 3 +. Но как тогда записать выражения, содержащие несколько


 

операторов? Например, как бы мы записали выражение, склады- вающее 4 и 3, а потом умножающее сумму на 10? Легко: 4 3 + 10 *.

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

 

Вычисление выражений в ОПЗ

Как мы можем вычислить результат? Представьте себе стек. Вы про- ходите по выражению слева направо. Если текущий элемент – чис- ло, его надо поместить (push – «втолкнуть») в стек. Если мы рассмат- риваем оператор, необходимо взять (pop – «вытолкнуть») два числа с вершины стека, применить к ним оператор и втолкнуть результат обратно в стек. Когда вы достигнете конца выражения, у вас долж- но остаться одно число, если, конечно, выражение было записано правильно. Это число и будет результатом.

Давайте разберём выражение 10 4 3 + 2 * –. Сначала мы поме- щаем 10 в стек; в стеке теперь содержится одно число. Следующий элемент – число 4, которое мы также помещаем в стек. То же про- делываем со следующей тройкой – стек теперь содержит 10, 4, 3. И наконец-то нам встречается оператор, а именно «плюс». Мы вы- талкиваем предыдущие два числа из стека (в стеке остаётся 10), скла- дываем их, помещаем результат в стек. Теперь в стеке 10, 7. Затал- киваем 2 в стек, теперь там 10, 7, 2. Мы снова дошли до оператора; вытолкнем 7 и 2 из стека, перемножим их, положим результат в стек. Умножение 7 на 2 даст 14; в стеке будет 10, 14. Получаем последний

 
 


 

оператор – «минус». Выталкиваем 10 и 14 из стека, вычитаем 10 из 14, получаем –4, помещаем число в стек, и так как у нас больше нет чисел и операторов для разбора, мы получили конечный результат! Теперь, когда мы знаем, как вычислять выражения на ОПЗ вручную, давайте подумаем, как бы нам написать функцию на языке

Haskell, которая делает то же самое.





Последнее изменение этой страницы: 2017-02-17; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 75.101.243.64 (0.01 с.)