【问题标题】:How to use Handlers that don't have SomeException as their argument type如何使用没有 SomeException 作为参数类型的处理程序
【发布时间】:2018-03-05 06:42:06
【问题描述】:

当使用Control.Monad.Throw(即exceptions 包)时,让我感到困惑的是,似乎我所有的投掷和接球都必须与SomeException 一起使用。

例如

value :: Either ExitCode String
value = throwM $ ExitFailure 23

在我看来它应该可以编译,因为throwM :: (Exception e, MonadThrow m) => e -> m aExitCode 有一个异常实例。即使这样也无法编译:

value :: Exception e => Either e String
value = throwM $ ExitFailure 23

事实上,它只有在我将签名更改为SomeException 时才会编译。我知道Exception 类型类有一个特殊的地方重新

documentation for Control.Exception 中,我可以看到他们将catches 与签名ArithException -> m a 或类似的处理程序一起使用的示例。我测试了它,它工作正常。

这在使用exceptions时是不可能的吗?

编辑 错误消息是:

由于使用了throwM,无法将类型ExitCodeSomeException 匹配

由于使用了throwM,无法将类型eSomeException 匹配

【问题讨论】:

  • 你得到什么错误信息?

标签: haskell exception-handling


【解决方案1】:

您看到的行为来自throwM 的类型签名:

throwM :: (Exception e, MonadThrow m) => e -> m a

Either 的实例,本质上是:

MonadThrow (Either SomeException)

这使得throwM:

throwM :: (Exception e) => e -> Either SomeException a

throwM for Either SomeException 可以取任意Exception e

但是,对于Either ExitCodeforall e. Exception e => Either e没有 MonadThrow 实例

问题在于,实际上并没有办法编写一个对所有e 都是多态的实例。想象一下有一个实例

Exception q => MonadThrow (Either q)

这将使throwM:

throwM :: (Exception e, Exception q) => e -> Either q a

这意味着您必须能够将 any e 转换为 any q,这不可能单独使用 Exception 类型类。

还可以想象一下,如果 Either ExitCode 有一个 MonadThrow 实例。这将使throwM 的类型签名:

throwM :: Exeption e => e -> Either ExitCode a

您可能会看到这显然是荒谬的,因为Exception 的许多实例无法强制转换为ExitCode。 (如果您不相信我,请尝试使用该类型签名编写一个函数!)

如果您只想Either 提供短路异常行为,请考虑:

  1. 只需使用Left 而不是throwM,并对catch 进行模式匹配。如果您真的仍然想使用Exception,可以使用fromException 尝试将SomeException 强制转换为您选择的Exception 实例。
  2. 您可以使用 exceptions 包,只要您必须假定异常可以是任何实例 (SomeException),捕获仍然有效。
  3. 使用 mtl 中的 MonadErrorExceptT,如果您想要某种具有捕获能力的多态接口

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    相关资源
    最近更新 更多