本文介绍了如何将Either转换为MonadThrow的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通过Either处理错误的函数:

I have a function that handles errors via Either:

funErrViaEither :: a -> Either SomeException b

我想在另一个应该更灵活并返回MonadThrow m的函数中使用此函数:

I want to use this function in another function that should be more flexible and return MonadThrow m:

funErrViaThrow :: MonadThrow m => a -> m b
funErrViaThrow x =
    if x = someCondition
        then funErrViaEither
        else throwM (SomeException MyCustomException)

这不能编译;类型检查器抱怨funErrViaEither的返回类型与预期的m b类型不匹配.我不明白为什么-Either具有MonadThrow的实例,而SomeExceptionLeft的类型.

This does not compile; the type checker complains that the return type of funErrViaEither does not match the expected type m b. I don't understand why - Either has an instance of MonadThrow with SomeException as the type of Left.

我在哪里犯错?将通过Either发出的错误转换为通过MonadThrow发出的错误的正确方法是什么?

Where do I err? What would be the correct way to convert an error signalled via Either into one signalled via MonadThrow?

推荐答案

虽然不能直接将funErrViaEither x :: Either SomeException b用作一般MonadThrow m => m b,但是可以使用模式匹配,适当地抛出或返回来处理Either :

While you can't use funErrViaEither x :: Either SomeException b directly as a general MonadThrow m => m b, you can process the Either using pattern matching, throwing or returning as appropriate:

case funErrViaEither x of
  Left err -> throwM err
  Right y -> return y

但是,我认为您可能已经用SomeException包裹了异常.从Either SomeException切换到MonadThrow m时,您更可能希望将其剥离,因此完整的类型检查示例如下所示:

However, I think you've probably over-wrapped your exceptions with SomeException. It's more likely that you want to peel this off when you switch from Either SomeException to MonadThrow m, so a full type-checked example would look like:

import Control.Monad.Catch

data MyCustomException = NoNegatives | NoOdds deriving (Show)
instance Exception MyCustomException

funErrViaEither :: Int -> Either SomeException Int
funErrViaEither n | n < 0     = throwM NoNegatives  -- or Left (SomeException NoNegatives)
                  | otherwise = Right $ n `div` 2

funErrViaThrow :: MonadThrow m => Int -> m Int
funErrViaThrow x =
    if even x
        then case funErrViaEither x of
               Left (SomeException err) -> throwM err  -- peel off SomeException
               Right y -> return y
        else throwM NoOdds

main = do
  print =<< funErrViaThrow 6
  (print =<< funErrViaThrow 5)
    `catch` (\err -> putStrLn $ "caught: " ++ show (err :: MyCustomException))
  print =<< funErrViaThrow (-2)

这篇关于如何将Either转换为MonadThrow的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 22:08