Треки
/
Elixir
Elixir
/
Вправи
/
Калькулятор зі зворотним польським записом
Калькулятор зі зворотним польським записом

Калькулятор зі зворотним польським записом

Навчальна вправа

Вступ

Помилки

Помилки трапляються. В Elixir, хоч часто кажуть «let it crash», бувають випадки, коли нам потрібно врятувати виклик функції до відомого робочого стану, щоб виконати контракт програмного забезпечення. У деяких мовах помилки використовують як засіб керування потоком виконання, але в Elixir цей підхід не схвалюють. Часто функції, які можуть спричинити помилку, можна розпізнати вже за їхньою назвою: функції, які спричиняють помилки, мають ! у кінці своєї назви. Це на противагу функціям, які повертають {:ok, value} або :error. Погляньмо на ці приклади з бібліотеки:

Map.fetch(%{a: 1}, :b)
# => :error
Map.fetch!(%{a: 1}, :b)
# => raises KeyError

Try/Rescue

Elixir надає конструкцію для рятування від помилок за допомогою try .. rescue

try do
  raise RuntimeError, "error"
rescue
  e in RuntimeError -> :error
end

Розгляньмо цю конструкцію:

  • Рядок 1, блок оголошено за допомогою try.
  • Рядок 2, тут розміщено виклик функції, який може спричинити помилку, у цьому випадку ми викликаємо raise/2.
  • Рядок 4, у розділі rescue ми зіставляємо зі зразком за назвою Module помилки, яку спричинено
    • з лівого боку від ->:
      • e зіставляється зі структурою помилки.
      • in - це ключове слово.
      • RuntimeError - це помилка, від якої ми хочемо врятуватися.
        • Якби ми хотіли врятуватися від усіх помилок, ми могли б використати _ замість назви модуля або взагалі опустити ключове слово in.
    • з правого боку:
      • інструкції, які буде виконано, якщо помилка збігається.

Структури помилок

Помилки (які іноді також називають «винятками»), від яких ми рятуємося в такий спосіб, є структурами. Рятування від помилок в Elixir трапляється дуже рідко. Зазвичай врятовану помилку записують у журнал або надсилають до зовнішнього сервісу моніторингу, а потім спричиняють її знову. Це означає, що зазвичай нас не цікавить внутрішня структура конкретної структури помилки.

У концепції «Винятки» ми дізнаємося більше про структури помилок, зокрема про те, як визначити власну помилку.

Вказівки

Працюючи в Instruments of Texas, ми отримуємо завдання попрацювати над експериментальним калькулятором зі зворотним польським записом [RPN], написаним на Elixir. У нашої команди проблема: деякі операції спричиняють помилки й призводять до аварійного завершення процесу. Наше завдання - написати функцію, яка обгортає функцію операції, щоб помилки можна було обробляти елегантніше, ідіоматичним кодом Elixir.

1. Попередити команду

Реалізуйте функцію calculate!/2, щоб викликати функцію операції, передаючи стек як єдиний аргумент. Функція операції визначена деінде, але відомо, що вона може або завершитися успішно, або спричинити помилку.

stack = []
operation = fn _ -> :ok end
RPNCalculator.calculate!(stack, operation)
# => :ok

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate!(stack, operation)
# => ** (ArgumentError) An error occurred

Імена функцій, що закінчуються на !, попереджають програмістів про те, що така функція може спричинити помилку

2. Обгорнути помилку

Під час додаткового дослідження ми помічаємо, що багато функцій використовують атоми й кортежі, щоб позначити свій успіх або невдачу. Реалізуйте calculate/2 за цією стратегією.

stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate(stack, operation)
# => {:ok, "operation completed"}

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate(stack, operation)
# => :error

3. Передати повідомлення

Деякі помилки містять важливу інформацію, яка потрібна колегам, щоб забезпечити правильну роботу системи. Реалізуйте calculate_verbose/2, щоб передати повідомлення про помилку. Помилка - це структура, яка має поле :message.

stack = []
operation = fn _ -> "operation completed" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:ok, "operation completed"}

stack = []
operation = fn _ -> raise ArgumentError, "An error occurred" end
RPNCalculator.calculate_verbose(stack, operation)
# => {:error, "An error occurred"}
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Elixir Exercism

Час розпочати Калькулятор зі зворотним польським записом?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Elixir, а також 58 концепцій168 вправ та справжнє наставництво від людей, і все це безкоштовно.