我正在尝试更好地了解Haskell中的错误状态,因为似乎有很多方法可以做到。理想情况下,我的数据结构将使任何无效输入都无法表示,但是尽管做出了很多努力,但我仍然偶尔会使用类型系统可以允许无效状态的数据。例如,让我们考虑我的程序输入是神经网络的训练结果。为了使数学有效,每个矩阵都必须具有正确的界线,并且类型系统不能(真正)表示该界线。如果数据无效,则应用程序实际上无能为力,只能停止任何进一步的处理并将问题通知某人(因此无法恢复)。在Haskell中处理此问题的最佳方法是什么?看来我可以做到:
1)处理数据时,请使用error
或其他部分函数。我的理解是,这仅应用于表示代码中的错误。因此,在我加载数据时,必须将其与某种形式的验证结合起来,而在“之后”进行检查的任何点,我都只是假设数据是有效格式。这对我来说很必要,而且似乎与惰性的声明性代码不太匹配。
2)使用Control.Exception.throw
处理数据时引发异常,然后将其捕获到顶层,在此我可以提醒某人。与error
相反,我认为这并不表示程序中存在错误,因此当我加载超出类型系统所能表示的范围的数据时,也许不会进行验证?处理数据时是否存在异常将定义验证。
3)将所有可能失败的数据处理提升到IO monad中,并使用Control.Exception.throwIO
。
4)提起所有可能无法进入IO monad的数据处理,并使用fail
(我已经读过使用fail
的社区不赞成的内容?)
5)返回Either
或类似内容,并通过您的所有逻辑使之冒泡。在某些情况下,我肯定无法完成Either
的编写。
6)使用Control.Monad.Exception,我只是略微了解它,但似乎涉及将任何可能失败的数据处理提升为某种特殊的monad,我认为它比Either
更容易组合?
,我什至不确定那是所有选项。有没有一种方法可以被社区普遍接受,或者这确实是一个自以为是的话题?