さて、Haskellのエラー処理の最初のルール:を使用しないでくださいerror
。
それはあらゆる点でひどいです。それは純粋に歴史の行為として存在し、プレリュードがそれを使用するという事実はひどいものです。使用しないでください。
あなたがそれを使用できる唯一の考えられる時間は、何かが非常に内部的にひどいとき、何かが現実のまさしくそのファブリックで間違っていなければならないときです。
質問はMaybe
vsになりEither
ます。Maybe
はhead
、値を返す場合と返さない場合がありますが、失敗する理由は1つだけです。Nothing
「壊れた、そして、あなたはすでにその理由を知っている」のようなことを言っています。一部の機能を示していると言う人もいます。
エラー処理の最も堅牢な形式はEither
、エラーADTです。
たとえば、私の趣味のコンパイラの1つには、次のようなものがあります。
data CompilerError = ParserError ParserError
| TCError TCError
...
| ImpossibleError String
data ParserError = ParserError (Int, Int) String
data TCError = CouldntUnify Ty Ty
| MissingDefinition Name
| InfiniteType Ty
...
type ErrorM m = ExceptT CompilerError m -- from MTL
ここで、エラータイプを多数定義し、それらをネストして、1つの素晴らしいトップレベルエラーを作成します。これは、コンパイルのどの段階からのエラーでもImpossibleError
、コンパイラのバグを意味するでも構いません。
これらのエラータイプはそれぞれ、きれいな印刷やその他の分析のために、できるだけ多くの情報を保持しようとします。さらに重要なのは、文字列を持たないことで、型チェッカーを介して不正な型のプログラムを実行すると、実際に統合エラーが生成されることをテストできることです!何かがになるとString
、それは永遠に消え、そこに含まれる情報はすべてコンパイラー/テストEither String
にとって不透明であるため、どちらも素晴らしいものではありません。
最後にExceptT
、この型をMTLからの新しいモナド変換子にパックします。これは基本的EitherT
に、純粋で快適な方法でエラーをスローおよびキャッチするための機能の素晴らしいバッチが付属しています。
最後に、Haskellには、例外をキャッチすることを除いて、他の言語と同様に例外の処理をサポートするメカニズムがあることに言及する価値がありますIO
。IO
すべてが潜在的に失敗する可能性のある重いアプリケーションにこれらを使用することを好む人もいますが、あまり頻繁ではないので、それについて考えるのが好きではありません。これらの不純な例外を使用するか、それとも単にExceptT Error IO
好みの問題です。個人的にExceptT
は、失敗の可能性を思い出すのが好きだから選びます。
要約すると、
Maybe
-私は1つの明らかな方法で失敗することができます
Either CustomType
-私は失敗することができます、そして何が起こったのかを教えます
IO
+例外-私は時々失敗します。ドキュメントをチェックして、実行時にスローするものを確認します
error
-私もあなたが嫌いです
head
またはlast
使用しているように見えるという事実に基づいて自分自身を推測していたerror
ので、それが実際に物事を行うのに良い方法であり、何かが欠けているだけだと思っていました。これはその質問に答えます。:)