为什么异常没有被'catch`捕获?

时间:2017-12-14 15:10:46

标签: haskell exception exception-handling

为什么这不会捕获转换conv B3的异常?!

import qualified Control.Monad.Catch as E
data A = A1|A2 deriving (Enum, Show)
data B = B1|B2|B3 deriving (Enum, Show)
conv b = safeConv
  where
    catchError e = Left e
    safeConv = (Right $ (toEnum $ fromEnum b :: A)) `E.catch` catchError

我得到了:

Right *** Exception: toEnum{A}: tag (2) is outside of enumeration's range (0,1)
CallStack (from HasCallStack):
  error, called at xxx.hs:227:26 in main:Main

2 个答案:

答案 0 :(得分:1)

Haskell异常与Java或C ++略有不同:" true"例外工作在IO monad中,然后通过纯粹的方式模仿异常,如ExceptT中所述。

toEnum函数抛出第一种 - IO异常, - 无法在纯代码中捕获。他们飞到最近的IO地方,在你的情况下显然是GHCi。

为了捕获此类异常,您首先需要通过Control.Exception.evaluate将投掷表达式包装在IO中。然后,您可以使用catch捕获此类异常,或者,如果您只想将其转换为Either exception A(正如您似乎正在做的那样),那么就有一个应用程序! - 它被称为try

此外,在使用catchtry时,您需要指定您尝试捕获的异常的特定类型。但it is possible to catch all exceptions无论使用存在类型SomeException而无论类型如何。

所以,结束所有这些,我们得到这个代码:

import qualified Control.Exception as E

data A = A1|A2 deriving (Enum, Show)
data B = B1|B2|B3 deriving (Enum, Show)

conv :: Enum b => b -> IO (Either E.SomeException A)
conv b = E.try . E.evaluate . toEnum $ fromEnum b

注意1 conv上的类型注释是必要的,以便将E.SomeException指定为要捕获的异常类型。没有它,GHC会抱怨异常的类型不明确。

注意2 :由于conv上的类型注释已指定目标类型A,因此不再需要toEnum $ fromEnum b上的类型注释。

注意3 :我已将Control.Monad.Catch的导入替换为Control.Exception,因为evaluateSomeException位于@ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource(){ byte[] encryptedFile = fileRetriever.getFile(bucket, key); String unencryptedJson = fileDecrypter.decryptFile(encryptedFile); JSONParser parser = new JSONParser(); JSONObject jsonObject = null; try{ jsonObject = (JSONObject) parser.parse(unencryptedJson); }catch (Exception ex){ log.error(ex.getMessage()); } String password = (String)jsonObject.get("password"); DataSource ds = DataSourceBuilder .create() .url(url) .username(userName) .password(password) .build(); return ds; } 之内

答案 1 :(得分:-1)

如果有人需要解决方案,我会留在这里。为了保持功能纯净,转换应该是:

unsafeConvEnum :: (Enum a, Enum b) => a -> b
unsafeConvEnum = toEnum . fromEnum

convEnum :: (Enum a, Enum b) => a -> Maybe b
convEnum e = unsafePerformIO conv'
  where onError (_::SomeException) = pure Nothing
        conv' = (Just <$> evaluate (unsafeConvEnum e)) `catch` onError

没有任何IO:)