在阅读network
package的源代码时,我注意到ioError (userError ("Error description"))
被广泛用于在IO操作期间引发错误。
由于这不是我第一次看到这一点,我想知道使用此模式而不是error
功能 practice 的区别是什么来自Prelude
。
我知道ioError . userError
在IO
monad中引发IOException
,而error
在任何地方引发ErrorCall
,但最终两者似乎注定要中止显示简单错误信息的程序。
在哪些情况下ioError . userError
优于error
?
答案 0 :(得分:8)
通常只使用error
来表示错误。从某种意义上讲,开发人员期望永远不会发生的事情就是一个错误。虽然error
确实只是抛出一个ErrorCall
异常,因此它可以像任何其他异常一样被捕获,但通常永远不会捕获它,因此程序崩溃通知最终用户将消息作为参数提供给error
的错误。稍后,用户可以在问题跟踪器上发布该信息,例如。
IOException
意味着被捕获,只是标准C / Java控制流程的改编。 userError
通常用于指定一般情况,而AlreadyExists
或ResourceBusy
都不合适。
必须提到的是,这两个问题的解决方案已经发生了变化。
对于错误报告,存在基于TemplateHaskell的库,例如the more specific types和loch-th,它们扩展error
以引用源代码中的特定位置和其他细节,例如“todo”假人,让编译通过,但有警告。
任何类型的例外通常被认为是对其他整洁的Haskell类型系统的攻击。最大的问题是你和编译器都没有关于是否进行某些计算的信息,例如: IO ()
,会引发任何异常。事实证明这是非常糟糕的,一些低级库引发的异常模式的出现深深地嵌套在依赖关系层次结构中,然后触发了一系列关于不同项目的错误报告并造成大量痛苦。这就是为什么最近一直在开发基于异常的控制流的完全替换,例如placeholders与相关的EitherT
monad transformer或errors util-library。这两种解决方案都会在类型系统中明确表示异常。但ErrorT
ErrorT
transformer支持EitherT
+“错误”。