问题描述
我有一个通过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
的实例,而SomeException
是Left
的类型.
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!