2016-03-24 6 views
1

私はsome EitherT monad transformer, as suggested from real world haskell chapter 18と書こうとしていました。失敗すると、String以外の引数を取ることができますか?

newtype EitherT e m a = EitherT { 
    runEitherT :: m (Either e a) 
} 

EitherTはそのEitherタイプのLeft errorRight resultを持つことになり、エラーとしてそれらを保つ、left値で停止している間Right値を生成するすべての計算をバインドします。

私のコードは、以下の(命令的スタイルのために申し訳ありません)です:

bindET :: (Monad m) => (EitherT e m a) -> (a -> EitherT e m b) -> (EitherT e m b) 
x `bindET` f = EitherT $ do 
    mx <- runEitherT x 
    case mx of 
     Right success -> runEitherT (f success) 
     Left error -> return (Left error) 


instance (Monad m) => Monad (EitherT e m) where 
    return a = EitherT $ return (Right a) 
    (>>=) = bindET 
    fail e = EitherT $ return (Left e) 

私は、EitherT変圧器は非常に簡単だったためMonadインスタンスを書いて思った私は、GHCiのにコードをロードするときしかし、私はこの不可解なエラーメッセージが表示されます。

EitherT.hs:30:18: 
    Could not deduce (e ~ [Char]) 
    from the context (Monad m) 
     bound by the instance declaration at EitherT.hs:27:10-41 
     `e' is a rigid type variable bound by 
      the instance declaration at EitherT.hs:27:10 
    Expected type: EitherT e m a 
     Actual type: EitherT String m a 
    In the expression: EitherT $ return (Left e) 
    In an equation for `fail': fail e = EitherT $ return (Left e) 
    In the instance declaration for `Monad (EitherT e m)' 
Failed, modules loaded: none. 

fail関数は引数としてStringを取るように固定されているようだ - そのような場合も、その後、私のEitherT e m aEitherT String m a AになりますすべてLeftの値はLeft Stringになります。 EitherTモナドは計算のエラーを示すために任意のタイプの値をLeftとして取ってほしいです。それをどうすれば実現できますか?

+1

これは実際問題であり、歴史的には断片化が起こりました。 ['EitherT'](https://hackage.haskell.org/package/either-4.4.1/docs/Control-Monad-Trans-Either.html#t:EitherT)、[' ErrorT'](https:///hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Error.html#t:ErrorT)、['ExceptT'](https://hackage.haskell.org/package/mtl) -2.2.1/docs/Control-Monad-Except.html#t:ExceptT)はすべて、探索したい解決策の空間内の微妙に異なる点を表します。 –

答えて

1

EitherTMonadErrorのインスタンスで、throwError :: e -> EitherT e m aとなります。教育上の理由から自分でEitherTを実装している場合は、上記のリンクでMonadErrorを検索し、独自のErrorTタイプをそのインスタンスにすることもできます。あなたが気づいaとbのように、それは意味がない場合でも、それを実装するモナドを強制的に、Monadであるため、それは、Stringに結びついているので

failは、一般的に、貧しいインターフェースと考えられています。

+0

私はエラーのためにいくつかのエラー報告プロトコル( 'mtl'の場合は' throwError'など)を導入し、 'fail = error'(haskellのデフォルト実装)のままにしておきます。 – thkang

0

あなたがそのようにfailを使用する場合は、EitherT String mとしてモナドを定義することができます。

instance (Monad m) => Monad (EitherT String m) where 
    -- ... 

エラーはとにかく通常文字列であるので、これは、それは見た目ほど役に立ちません。

このようにすると、パターンマッチの失敗を処理できるという利点があります。あなたはより少なくより有益なエラーメッセージ"pattern match failure in ..."ではなく"couldn't get the thing, try restarting the server"のようなものを得るである(例えば)Just

do 
    Just a <- lift getTheThing 
    lift (print a) 

欠点を返す必要があるアクションを呼び出したい場合、これは便利である可能性があります。

CactusのようにthrowErrorを使用すると、失敗したときに手動で呼び出すことができます。

関連する問題