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

Aiv*_*var 6 haskell types

我正在阅读关于Haskell指称语义(http://en.wikibooks.org/wiki/Haskell/Denotational_semantics)的内容,我不明白为什么在类型中,底部"值"被置于另一个级别而不是"正常"值,例如为什么它不能模式匹配.

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

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

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

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

scl*_*clv 17

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

所以每个图灵完整的语言都有底.

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

换句话说,因为底部是不可避免的(在图灵完整的世界中),那么除了邀请错误之外,还有什么可以使一切都可以为空?

还要注意,尽管Prelude中的一些函数是出于历史原因的部分功能,但现代Haskell风格倾向于几乎在所有地方编写总函数,并Maybe在函数中使用显式返回类型,head否则这些函数将是部分函数.

  • @PhilipJF:如果你有一个指称方法,非终止始终是你的语义域中的一个值.如果你像Bob Harper一样并且不相信指称语义,你可以声称非终止是一种效果,它在ML中不存在.我认为鲍勃哈珀知道相当多,但我也认为斯科特和斯特拉奇在这方面比他更清楚. (4认同)
  • 我不认为这是公平的.在严格的语言中,非终止是一种效果,而在非严格的语言中,它是一种价值.你不能在ML中有一个"无人居住"类型的值,虽然你可以有一个函数*`a - > Void*因为函​​数而不是类型被解除. (2认同)
  • 我仍然认为我不明白你的目标是什么.我不是指称语义学的专家,但我认为CBV语言的标准模型使用pCpo并没有给你底部.所以`数据Nat = Z |的表示 S Nat`只是$\mathbb {Z} $(离散CPO).也许我错过了一些东西,但在ML中你不能有一个表示分歧的名字,尽管你可以有不同的表达方式. (2认同)

Phi*_* JF 14

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

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

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

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

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

Integer
Run Code Online (Sandbox Code Playgroud)

对于已知不是例外的整数类型

?Integer
Run Code Online (Sandbox Code Playgroud)

对于可能是异常的整数类型.答案是我们已经这样做了:Haskell在前奏中有一种类型

data Maybe a = Just a | Nothing
Run Code Online (Sandbox Code Playgroud)

这可以被解读为"一个a或根本没有".我们可以模式匹配,Maybe所以这个提议不给我们任何东西.(我们也有类似Either更丰富的"可能出错的计算"类型以及花哨的monad语法/组合器,以使这些类型易于使用).

那么,为什么要有例外呢?在Haskell中,除了IO monad之外,我们不能"捕获"异常.如果我们可以完美地模拟异常Maybe,Either为什么在语言中有例外?

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

(error "error 1") + (error "error 2") :: Integer
Run Code Online (Sandbox Code Playgroud)

这个表达式应该明显导致异常,但是哪个异常? (+)专门针对Integer的两个参数都是严格的,所以这样做无济于事.我们可以决定它是第一个值,但总的来说我们会有

x + y =/= y + x
Run Code Online (Sandbox Code Playgroud)

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