hgi*_*sel 2 haskell exception-handling
在使用Control.Monad.Throw(即exceptions包)时,让我感到困惑的是,似乎我所有的投掷和接球都必须使用SomeException.
例如
value :: Either ExitCode String
value = throwM $ ExitFailure 23
Run Code Online (Sandbox Code Playgroud)
这在我看来应该编译,因为throwM :: (Exception e, MonadThrow m) => e -> m a, 并且ExitCode有一个 Exception 实例。即使这样也不能编译:
value :: Exception e => Either e String
value = throwM $ ExitFailure 23
Run Code Online (Sandbox Code Playgroud)
实际上,它仅在我将签名更改为SomeException. 我知道Exception类型类有一个特殊的地方
在Control.Exception的文档中,我可以看到它们catches与签名ArithException -> m a或类似处理程序一起使用的示例。我测试了它并且它起作用了。
使用时这是不可能的exceptions吗?
编辑错误消息是:
无法匹配类型
ExitCode与使用SomeException引起的throwM
或者
无法匹配类型
e与使用SomeException引起的throwM
您看到的行为来自以下类型的签名throwM:
throwM :: (Exception e, MonadThrow m) => e -> m a
Run Code Online (Sandbox Code Playgroud)
和 的实例Either,本质上是:
MonadThrow (Either SomeException)
Run Code Online (Sandbox Code Playgroud)
这使得throwM:
throwM :: (Exception e) => e -> Either SomeException a
Run Code Online (Sandbox Code Playgroud)
throwM因为Either SomeException可以带任何Exception e。
但是,没有 MonadThrow 实例for Either ExitCode, 或 for forall e. Exception e => Either e。
问题是没有真正的方法可以编写一个对所有e. 想象一下有一个实例
Exception q => MonadThrow (Either q)
Run Code Online (Sandbox Code Playgroud)
这将使throwM:
throwM :: (Exception e, Exception q) => e -> Either q a
Run Code Online (Sandbox Code Playgroud)
这意味着您必须能够将any e转换为any q,而单独使用类型类是不可能的Exception。
还设想一下,如果有一个MonadThrow实例Either ExitCode。这将使类型签名为throwM:
throwM :: Exeption e => e -> Either ExitCode a
Run Code Online (Sandbox Code Playgroud)
您可能会看到这显然是荒谬的,因为有许多实例Exception不能强制转换为ExitCode. (如果您不相信我,请尝试使用该类型签名编写一个函数!)
如果您只想要 的短路异常行为Either,请考虑:
Left代替throwM, 和模式匹配即可catch。如果您真的想使用Exceptionstill,您可以使用fromException来尝试将 a 强制SomeException转换Exception为您选择的实例。SomeException) ,捕获仍然有效MonadError和ExceptTfrom mtl,如果您想要某种具有捕获能力的多态界面