RPN電卓

RPN電卓

学習演習

はじめに

エラー

エラーは起こるものです。Elixirでは、よく「クラッシュさせておけ」と言われますが、ソフトウェアの契約を果たすために、関数呼び出しを既知の正常な状態にまで捕捉しなければならないこともあります。言語によっては、エラーを制御フローの手段として使いますが、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セクションでは、発生したエラーの_モジュール_名に対してパターンマッチを行います。
    • ->の左側では、
      • eがエラー構造体にマッチします。
      • inはキーワードです。
      • RuntimeErrorは、捕捉したいエラーです。
        • すべてのエラーを捕捉したい場合は、モジュール名の代わりに_を使うか、inキーワードを完全に省略できます。
    • 右側では、
      • エラーがマッチしたときに実行される処理です。

エラー構造体

このようにして捕捉するエラー(「例外」と呼ばれることもあります)は、構造体です。 Elixirでエラーを捕捉することは、めったにありません。 通常は、捕捉したエラーをログに記録したり、外部の監視サービスに送信したりしたあと、もう一度発生させます。 つまり、特定のエラー構造体の内部構造を気にする必要は、通常ありません。

例外のコンセプトでは、エラー構造体についてさらに詳しく学べます。独自のカスタムエラーを定義する方法も含まれます。

説明

Instruments of Texas で働くあなたは、Elixirで書かれた実験的な逆ポーランド記法[RPN]の計算機の開発を任されました。チームでは、一部の演算でエラーが発生してプロセスがクラッシュするという問題が起きています。そこで、演算関数をラップし、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

RPN電卓を始める準備はできましたか?

Exercismに登録すれば、58個のコンセプト168個の演習、そして本物の人間によるメンタリングとともに、Elixirを学んでマスターできます。すべて無料です。