Haskell 如何将'throwM'与'Except'连用?

Haskell 如何将'throwM'与'Except'连用?,haskell,Haskell,有一个包的特点是单子 这个monad转换器扩展了monad,使其能够抛出异常 有一个具有此效果的软件包 抛出异常 所以看起来这两个人应该配合得很好。然而: λ runExcept $ throwM Overflow <interactive>:46:13: error: • No instance for (MonadThrow Data.Functor.Identity.Identity) arising from a use of ‘throwM’

有一个包的特点是单子

这个monad转换器扩展了monad,使其能够抛出异常

有一个具有此效果的软件包

抛出异常

所以看起来这两个人应该配合得很好。然而:

λ runExcept $ throwM Overflow

<interactive>:46:13: error:
    • No instance for (MonadThrow Data.Functor.Identity.Identity)
        arising from a use of ‘throwM’
    • In the second argument of ‘($)’, namely ‘throwM Overflow’
      In the expression: runExcept $ throwM Overflow
      In an equation for ‘it’: it = runExcept $ throwM Overflo
λrun除了$throwM溢出
:46:13:错误:
•没有(MonadThrow Data.Functor.Identity.Identity)的实例
因使用“throwM”而产生
•在“($)”的第二个参数中,即“throwM Overflow”
在表达式中:runExcept$throwM Overflow
在“it”的方程式中:it=runExcept$throwM Overflo
我知道我可以用单子。但无论如何,我想
了解发生了什么。我不太熟悉monad transformers。

编译器通过以下方式推断类型:

  • 由于
    runExcept::Except ea->…
    ,因此
    runExcept
    的参数必须是
    Except ea
    类型
    所以,
    throwM溢出::除了ea
  • Except e a
    Except e Identity a
    的类型同义词
    所以,
    throwM溢出::除了标识a
  • 因为
    throwM::MonadThrow m=>e->ma
    ,编译器需要为匹配
    的类型找到
    throwM
    的一个实例,但不包括e标识
  • 看::
    MonadThrow m=>MonadThrow(不包括em)
    。它与任何
    m
    匹配,但该
    m
    还必须具有
    MonadThrow
    的实例
  • 匹配
    throwM Overflow
    的类型,即
    除了标识a
    ,以及定义
    MonadThrow
    实例的类型,即
    除了T m
    ,编译器确定
    m=Identity
  • 但是等等!根据实例定义
    MonadThrow m=>MonadThrow(em除外)
    ,这个
    m
    (我们现在知道它是
    Identity
    )也必须有一个
    MonadThrow
    实例
  • 因此编译器会查找它,但没有找到它
  • 并显示一条错误消息:“无实例
    MonadThrow标识
与类型类相关的错误消息可能令人烦恼。编译器并不总是告诉您它为了得出错误而遵循的完整结论链。这是不幸的,但这是什么呢

但这里的根本问题是除了
之外的
throwM
实际上并不兼容。也就是说,
throwM
抛出的错误与
抛出的错误不同,只是
包含错误。它们是两种不同的错误相关机制。要抛出与
不兼容的错误,请使用。这应该起作用:

> runExcept $ throwE Overflow
Left Overflow


据我目前所知,Haskell中的错误处理环境尚未稳定到可管理的状态。我们有
除了
,它被推广到
除了
throw
throw
throwIO
throwSTM
throwE
throwM
,所有这些都有来自不同库和不同单子下的变体。此外,
UnliftIO
的到来使事情变得更加复杂。这有点像
ExceptT
将因此消失。

我问了为什么没有这样的实例,我们将看看是否出现了什么。实例
MonadThrow Identity
不可能存在,因为异常会去哪里?当然
instance MonadThrow Except
可以。