2011-11-17 10 views
30

私はかなりハスケルを新しくしており、ゆっくりとモナドの存在に何か問題があるという考えを得ています。 Real World Haskell warns against its use(「もう一度、ほとんどの場合、失敗を避けることをお勧めします!」)。私は今、ロス・パターソンが「疣贅であり、デザイン・パターンではありません」とback in 2008と呼んでいることに気付きました(そしてそのスレッドでかなりの合意を得ているようです)。Monadの使用を避けるべきですか?

Dr RalfLämmeltalk on the essence of functional programmingを見て、私はモナドが失敗する可能性のある緊張を理解し始めました。講演では、基本モナドパーサー(ロギング、状態など)にさまざまなモナディック効果を追加することについてRalfが話します。エフェクトの多くは、ベースパーサーの変更と、使用されるデータ型の変更が必要でした。私は、すべてのモナドに「失敗」を追加することは、「失敗」が非常に一般的で、可能な限り「ベース」パーサー(または何でも)への変更を避けるために妥協であったかもしれないと考えました。もちろん、ある種の「失敗」はパーサーには意味がありますが、必ずしも状態を入れたり取得したりすることはできません。

私が間違ったトラックに乗る可能性があるかどうか教えてください。

モナドの使用を避けるべきですか? Monadに代わる方法は何ですか? この「デザインの疣贅」を含まない代替モナド図書館はありますか? このデザイン決定の歴史に関する詳細はどこで確認できますか?

+4

[Real World Haskell says](http://book.realworldhaskell.org/read/monads.html#monads.monad.fail) "[多くのモナドでは]' fail'は 'error'を使用しています。呼び出し元が捕まえることができない、または期待しないという例外をスローするため、通常は非常に好ましくありません。 – Miikka

+3

短い答え:はい。 –

+2

"Just x < - somethingReturningIoMaybe"のように、パターンマッチの失敗を処理するには "失敗"が必要だと思います。 –

答えて

27

いくつかのモナドは、顕著な故障メカニズムを有する。端末モナド:

data Fail x = Fail 

いくつかのモナドは、例えば、賢明な故障メカニズム(undefinedが賢明ではない)を持っていません最初のモナド:その意味で

data Return x = Return x 

は、それが明確にfail方法を持っているすべてのモナドを必要とするいぼです。モナド(Monad m) =>を抽象化したプログラムを書くなら、その汎用的なmfailメソッドを使うのはそれほど健康ではありません。これは、failが本当に存在すべきではないモナドでインスタンス化できる関数になります。

私は良いfail行動が明確に規定された特定のモナドでの作業時(Pat <- computationを照合することによって、特に間接的に)failを使用して少数の異議を参照してください。そのようなプログラムは、ちょうどMonadの代わりにMonadZeroの要求を生み出した古いパターンに復帰しても、うまくいくでしょう。

よりよい規律は、常に失敗のケースを明示的に扱うことであると主張するかもしれません。 (1)モナディプログラミングのポイントは、そのような混乱を避けることであること、(2)モナディ計算の結果に関するケース分析の現在の表記法は非常にひどいことである。 SHEの次のリリースは少しを助けるかもしれない(また、他の変異体で見つかった)表記

case <- computation of 
    Pat_1 -> computation_1 
    ... 
    Pat_n -> computation_n 

をサポートします。

しかし、この状況は残念です。モナドをサポートする操作によってモナドを特徴付けることは、しばしば役に立ちます。いくつかのモナドでサポートされている操作としてfailthrowなどが表示されますが、他のものはサポートされていません。 Haskellは、利用可能な一連の操作の小さなローカライズされた変更をサポートするのは非常に不器用で高価です。古い操作でそれらを処理する方法を説明することによって新しい操作を導入します。ここでもっとうまくやってみたいと思ったら、catchの動作を再考して、と異なるローカルエラー処理機構の翻訳者にする必要があります。私はしばしば、エラーに合格する前により多くのコンテキスト情報を追加するハンドラと(パターンマッチの失敗などによって)情報を失う可能性のある計算を括弧で囲む必要があります。私は、そうするのが時々それよりも難しいと感じるのを助けることができません。

これは問題はありませんが、少なくとも実現可能な特定のモナドに対してはfailを使用し、「例外」を適切に処理してください。

+0

すみません、それは何ですか? –

+1

これはStrathclyde Haskell Enhancementです。私のプリプロセッサは実験的な機能(ほとんどが偽の依存型)をサポートしています。しかし、最近では、SHHはその機能の多くをGHCに採用することで冗長化されています。 – pigworker

24

ハスケル1.4(1997)には、failはありませんでした。代わりにzeroメソッドを含むMonadZeroタイプのクラスがありました。今、doの表記では、パターンマッチの失敗を示すためにzeroが使用されました。これは人に驚きをもたらしました。彼らの機能がMonadMonadZeroかどうかは、その中でdoという表記をどのように使用したかによって決まりました。

Haskell 98が少し後に設計されたとき、初心者にとってプログラミングが簡単になるようにいくつかの変更が加えられました。例えば、モナドの理解はリストの理解に変わった。同様に、doタイプのクラスの問題を削除するには、MonadZeroクラスが削除されました。 doの使用については、方法failMonadに加えた。 zeroの他の用途では、mzeroの方法をMonadPlusに追加しました。

failは明示的に使用するべきではないという良い議論があります。その唯一の使用目的は、do表記の翻訳です。それにもかかわらず、私自身はしばしばいたずらして、明示的にfailを使用します。

元の1.4と98のレポートhereにアクセスできます。私は変更につながる議論がいくつかの電子メールリストのアーカイブで見つけられると確信していますが、私はリンクを手軽に持っていません。

+0

を使うべきです。"私自身はしばしばいたずらにして、明示的に 'fail'を使います。しばしば?説明する。 –

+6

@ダンバートン:何が説明する必要がありますか?私がモナドな状況にいる場合、別のメカニズムを使用する必要がある場合を除いて、失敗を通知するために「失敗」を使用する傾向があります。 – ibid

+0

ありがとうございます。歴史について聞くのは良いことです。私はハスケルがもともと唯一の表記法を持っていたことを知らなかった(リスト内包表記なし)。私はメーリングリストのアーカイブhttp://www.mail-archive.com/[email protected]/msg03002.htmlに興味深いスレッドを見つけました –

6

私は可能な限りモナドが失敗するのを避けようとしており、状況に応じてさまざまな方法で失敗をキャプチャする方法があります。エドワード・ヤン氏はブログで「8 ways to report errors in Haskell revisited」というタイトルの記事を書いています。要約すると

、彼が特定したエラーを報告するためにさまざまな方法があります:

  1. 使用エラー
  2. たぶん使用
  3. 使用いずれかの文字列
  4. 使用モナドと1-一般化に失敗3
  5. MonadErrorとカスタムエラータイプを使用する
  6. IOモナドでスローを使用
  7. 私は、エラーを処理する方法を知っていればモナド変圧器
  8. チェック例外これらのうち
  9. 失敗

  • 使用がioErrorとキャッチ
  • 移動ナットが、私はEither e bで、オプション3を使用するように誘惑されるだろうもう少し文脈が必要です。

  • +1

    または 'おそらく' ...いずれかを使用するといいです。それは、どちらかといえば同じコードで使用するライブラリとライブラリを使用するライブラリを使用すると面倒です。モナド変圧器はあまりいいものではありません... – alternative

    関連する問題