为什么Haskell case语句中的默认catch-all不是必需的?

时间:2016-06-13 04:55:09

标签: haskell

Haskell以安全语言而闻名。通常会将更多可能的编程错误推送到编译时错误,并减少运行时间。

这方面的一个例子是if表达式。 if中的else始终是强制性的。你需要掩盖两种可能性。这很好,因为您已经考虑并涵盖了运行时将发生的所有可能性。

现在Haskell有一个case表达式。 (这与其他OO和命令式语言中的switch语句有一些相似之处 - 但Haskell在类型系统中增加了很多丰富性。

describeList :: [a]
describeList xs = "The list is " ++ case cs of [] -> "empty."
                                               [x] -> "a singleton list."
                                               xs -> "a longer list."

但是使用case表达式,默认的'catch-all'不是必需的。

对我而言,这听起来会导致运行时错误。

我的问题是:为什么默认的catch-all在Haskell case语句中不是强制性的?

2 个答案:

答案 0 :(得分:7)

Haskell肯定比其他语言更安全更安全,尤其是主流语言,但它远非100%安全。 Haskell中的其他不安全功能包括编写无限循环的功能,如let x = x in xunsafePerformIOerrorundefined。我想你可以说这只是方便和安全之间的权衡。

在比简单示例更复杂的代码中,有时会出现一些您知道不会发生的情况,因此您将它们排除在case表达式之外,但Haskell的类型系统不够强大编译器能够知道那些丢失的案例是不可能的。 (例如,您可能正在计算一些只能返回数字345的数学函数,但这个事实是由于您碰巧知道的一些困难定理并且编译器不知道。)

对于它的价值,您可以将-fwarn-incomplete-patterns传递给ghc编译器,以便在编译时错过case语句中的分支(如果您愿意)。这包含在-W选项中,可以打开几个常见的编译器警告。

答案 1 :(得分:4)

并不总是需要一个包罗万象的东西。如果明确处理所有情况(模式匹配穷举),则永远不会达到全部案例。

我可以想到一个强制性捕获所有情况的严重缺点:如果扩展ADT(代数数据类型),依赖代码仍然会编译,程序员不会被提醒他们应该处理的额外情况。