1

さまざまなコンストラクターを持つカスタムエラータイプがあります。それを呼び出しましょうMyError:

data MyError = ConditionA String | ConditionB String | ConditionC String

コンストラクターはエラーの種類を分類し、文字列は追加の詳細を提供します。モナドでエラータイプを使用しEitherたい、例えば次のような関数が欲しい

myFunction :: a -> Either MyError a

maybeToEithermyFunction 内で、MissingH の関数を使用したいData.Either.Utils:

maybeToEither :: MonadError e m => e -> Maybe a -> m a

MyErrorしかし、ghc は、これを行うには、作成してインスタンス化する必要があると教えてくれますError。これは、 がモナドである必要があり、 のモナド インスタンスが次の理由でMonadError必要であるという事実に帰着するようです。mEither eError efail

instance (Error e) => Monad (Either e) where
    return        = Right
    Left  l >>= _ = Left l
    Right r >>= k = k r
    fail msg      = Left (strMsg msg)

Errorでは、無意味なインスタンス宣言を避けるにはどうすればよいMyErrorでしょうか。

Database.MongoDB.Queryの作成者がデータ型に同じ問題を抱えていることに気付きましたFailure(これには複数のコンストラクターがあるため、適切なインスタンスがありません)。彼らの解決策は、の使用をエラーとしてError扱うことでした。fail

instance Error Failure where strMsg = error

それが私の最良の選択肢ですか?

4

2 に答える 2

3

これには MissingH ライブラリを使用しないでください。GHC コンパイラのすべてのバージョンにバンドルされているベース ライブラリを使用するだけです。コードが何らかの本質的な理由で (mtl ライブラリの) クラスを明示的に使用する必要がない限り、MonadErrorそのクラスの使用を避けることができるため、Errorエラー型のインスタンスの必要性を回避できます。

2010 年 11 月にリリースされたベース ライブラリのバージョン 4.3 以降では、 の標準Monadインスタンスはのインスタンスである必要はありEither eませ。したがって、次の行を含めることができますeError

import Control.Monad.Instances ()

モジュールの上部に配置し、型Either MyErrorを自由に使用Monadします。

MissingH の代わりにこの関数を使用しますmaybeToEither

maybeToEither :: e -> Maybe a -> Either e a
maybeToEither e = maybe (Left e) Right

MonadErrorのインスタンスが本当に必要な場合は、タイプをEither変更して、人為的な方法でインスタンスを提供する必要があります。その方法に関するより詳細な提案については、@jozefg の回答を参照してください。それでも、個人的には、このような単純なもののために MissingH ライブラリ全体を取り込むことはしません。MyErrorError

于 2013-09-30T16:19:04.473 に答える
1

3つの選択肢があります

  1. にケースを追加MyError

    data MyError = FailCase String
                 | ...
    

    それは簡単ですが、ちょっと醜いです。

  2. に渡すerror

    これは DB ハンドルの dd ですが、実行時エラーが発生するため、おそらくこれは回避する必要があります。

  3. (または、またはエラーケースを処理するための他のもの)でラップMyErrorします。EitherMaybe

    type MyErrorMonad = Either (Either String MyError)
    

    次に、いくつかの類義語を定義するだけです。これはタイピングが多いですが、おそらく最も概念的にクリーンです。failまた、が呼び出されるケースを明示的に処理する必要があります。

    caseA = Right . CaseA
    ....
    

    instance Error (Either String b) where strMsg = Left
    
于 2013-09-30T14:43:14.927 に答える