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`
и т. д.). Так нам удобнее, потому что мы можем легко разобрать подобную формулу в уме. Но у такой записи есть и негативное свойство: приходится использовать скобки для обозначения приоритета операций.
Вычисление выражений в ОПЗ
Как мы можем вычислить результат? Представьте себе стек. Вы проходите по выражению слева направо. Если текущий элемент – число, его надо поместить (
Давайте разберём выражение 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, которая делает то же самое.
Реализация функции вычисления выражений в ОПЗ
Наша функция будет принимать строку, содержащую выражение в обратной польской записи, например, "10 4 3 + 2 * -"
, и возвращать нам результат вычисления этого выражения.