Haskell中的异常如何工作?


86

在GHCi中:

Prelude> error (error "")
*** Exception: 
Prelude> (error . error) ""
*** Exception: *** Exception: 

为什么第一个不是嵌套异常?


9
这是GHC可以进行的一种转换:“我是自己操作的编译器,所有_ | _s都对我相似”。您是否在要求使这两行编译不同的实现细节?
shachaf 2012年

3
error是特殊的,并不是真正的异常机制。有关真正的,可捕获的异常,请参见Errormonad。
Cat Plus Plus

1
请注意,例如,即使该功能等效于,其(\f g x -> f (g x)) error error ""行为也不同于。可能与Prelude编译时使用的优​​化标志有关。(.) error error ""(.)
shachaf 2012年

5
iterate error "" !! n真棒fix error
Vitus 2012年

9
我总是假装error = error并相应地编程。
加布里埃尔·冈萨雷斯

Answers:


101

答案是,这是不精确异常的(有点令人惊讶)语义

当纯代码可以显示为一异常值(即error或的值 undefined,而明确地不是IO中生成的异常的类型)时,则该语言允许返回该组的任何值。Haskell中的异常值更像NaN是浮点代码,而不是命令式语言中基于控制流的异常。

甚至对于高级Haskeller来说,偶尔也会遇到这样的情况:

 case x of
   1 -> error "One"
   _ -> error "Not one"

由于代码会评估一组异常,因此GHC可以自由选择一个。启用优化后,您很可能会发现此结果始终为“ Notone”。

我们为什么要做这个?因为否则我们会过度限制语言的评估顺序,例如,我们将不得不为以下问题确定确定性的结果:

 f (error "a") (error "b")

例如,如果存在错误值,则要求从左到右进行评估。非常不客气!

由于我们不想牺牲仅仅为了支持代码而可以进行的优化error,因此解决方案是指定结果是一组异常值中的不确定性选择:不精确的异常!以某种方式,将返回所有异常,然后选择一个。

通常,您不在乎-异常就是异常-除非您关心异常内的字符串,否则在这种情况下使用error调试会造成极大的混乱。


参考文献:不精确异常的语义,Simon Peyton Jones,Alastair Reid,Tony Hoare,Simon Marlow,Fergus Henderson。Proc编程语言设计与实现(PLDI'99),亚特兰大。(PDF


2
我了解GHC选择了可能遇到的任何例外之一。但是在您的“案例”示例中,输入1不会遇到“一个”异常,因此我仍将其归类为错误。
Peaker

8
@Peaker无效代码elim-优化器无需查看x即可看到结果为错误,所有分支均产生“相同”值,因此它可以完全忽略输入值。在错误的情况下,不是错误!
Don Stewart

1
@lpsmith:我认为所有异常类型都不精确(当使用抛出时throw),您可以确定地使用引发异常throwIO
FunctorSalad 2012年

4
@Peaker我认为你是对的。我不认为ghc如果要遵守不精确的例外情况文件中列出的规则,就不应该优化此表达式。
2012

3
什么是不精确的异常纸确实好像说的是,如果情况scrutinee是一个错误值,可以返回从树枝上则误差值。所以case error "banana" of (x:xs) -> error "bonobo"可以给你* Exception: bonobo
本·米尔伍德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.