为什么Haskell在部分函数中使用bottom而不是null?

时间:2013-02-03 20:07:07

标签: haskell types

我正在阅读有关Haskell指称语义(http://en.wikibooks.org/wiki/Haskell/Denotational_semantics)的内容,我不明白为什么在类型中,底部“值”与“正常”值相比处于另一个级别,例如为什么它可以'模式匹配。

我认为模式修补底部会导致麻烦,因为底部也表示非终止计算,但为什么非终止计算和错误应该被视为相同? (我假设使用不支持的参数调用部分函数可以被视为错误)。

如果所有Haskell类型都包含模式匹配的Java-null-like值而不是bottom?那么有什么有用的属性会丢失?

换句话说:为什么通过提升所有具有空值的类型来使所有Haskell函数完全不是明智的呢?

(非终止计算是否需要特殊类型?)

2 个答案:

答案 0 :(得分:17)

在不限制语言的图灵完整性的情况下,你无法摆脱非终止,并且通过暂停问题,我们通常无法检测到非终止并将其替换为值。

所以每个 turing完整语言都有底。

Haskell和Java之间的唯一区别是Java底部为为null。 Haskell没有后者,这很方便因为我们不必检查空值!

换句话说,因为底部是不可避免的(在turing完整世界中),那么除了邀请错误之外,使得所有内容都可以为空的重点是什么?< / p>

同时请注意,虽然Prelude中的某些函数是出于历史原因的部分功能,但现代Haskell风格倾向于在几乎所有地方编写总函数,并在诸如Maybe之类的函数中使用显式head返回类型否则是偏袒的。

答案 1 :(得分:14)

我对这些评论中的狡辩,我认为sclv回答了你问题的第一部分,但至于

  

如果所有Haskell类型都包含模式匹配的Java-null-like值而不是bottom?那么有什么有用的属性会丢失?

     

换句话说:为什么通过提升所有具有空值的类型来使所有Haskell函数完全不是明智的呢?

在这里,您似乎正在区分非终止和异常。那么,虽然在非终止时模式匹配是不可能的(因为停止问题),为什么不能在异常上进行模式匹配?

我回答了我自己的问题:那些从不抛出异常的函数呢?毕竟,Haskell具有全部功能。我不应该模式匹配,以确保某些东西是非特殊的,如果它已知是非特殊的。 Haskell作为一种束缚和纪律语言,自然希望在类型中传达这种差异。也许通过写作

Integer

表示已知非常例的整数类型

?Integer

表示可能是异常的整数类型。答案是我们已经这样做了:Haskell在前奏中有一个类型

data Maybe a = Just a | Nothing

可以被理解为“a或根本没有。”我们可以在Maybe上进行模式匹配,因此此提案不会给我们任何帮助。 (我们也有像Either这样的类型,用于更丰富的“可能出错的计算”以及花哨的monad语法/组合,以使这些类型易于使用)。

那么,为什么例外呢?在Haskell中,除了IO monad之外,我们不能“捕获”异常。如果我们可以使用MaybeEither完美地模拟异常,为什么会有语言异常?

这有几个答案,但核心是 Haskell异常是不精确的。可能会出现异常,因为您的程序内存不足,或者您执行的线程被另一个线程或其他一些不可预测的原因杀死。此外,通常有例外我们关心我们得出的例外。那么下面的表达式应该是什么?

(error "error 1") + (error "error 2") :: Integer

这个表达式应该明显导致异常,但是哪个异常?专门针对Integer的(+)在两个参数中都是严格的,所以这不会有帮助。我们可以决定它是第一个值,但一般来说我们会有

x + y =/= y + x

这将限制我们的等式推理选项。 Haskell提供了具有不精确行为的异常概念,这很重要,因为语言的纯粹部分具有完全精确的行为并且可能是限制性的。