我目前正在努力思考在 Haskell 中使用异常的正确方法。异常的工作原理很简单;我试图清楚地了解解释它们的正确方法。
基本立场是,在一个设计良好的应用程序中,异常不应该逃到顶层。任何出现的异常显然是设计者没有预料到的——即,程序错误(例如,除以零),而不是不寻常的运行时发生(例如,找不到文件)。
为此,我编写了一个简单的顶级异常处理程序,它捕获所有异常并打印一条消息以stderr
说明“这是一个错误”(在重新抛出异常以终止程序之前)。
但是,假设用户按下 Ctrl+C。这会导致抛出异常。显然,这不是任何类型的程序错误。但是,未能预测和响应这样的用户中止可能被视为错误。所以也许程序应该捕捉到它并适当地处理它,在退出之前进行任何必要的清理。
但问题是……处理此问题的代码将捕获异常,释放任何资源或其他任何东西,然后重新抛出异常!因此,如果异常进入顶层,那并不一定意味着它没有被处理。这只是意味着我们想快速退出。
所以,我的问题是:异常是否应该以这种方式用于流量控制?每个显式捕获的函数都应该UserInterrupt
使用显式的流控制结构来手动退出而不是重新抛出异常吗?(但是调用者怎么知道也退出?)UserInterrupt
到达顶层可以吗?但是在那种情况下,ThreadKilled
同样的论点也可以吗?
简而言之,中断处理程序是否应该为UserInterrupt
(并且可能ThreadKilled
)做一个特殊情况?一个HeapOverflow
orStackOverflow
呢?那是一个错误吗?还是“程序无法控制的情况”?