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