How to convert Either to MonadThrow

夙愿已清 提交于 2020-06-16 07:18:15

问题


I have a function that handles errors via Either:

funErrViaEither :: a -> Either SomeException b

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)

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.

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


回答1:


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

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)


来源:https://stackoverflow.com/questions/62362053/how-to-convert-either-to-monadthrow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!