Haskell 中的 undefined 和 Java 中的 null 有什么区别?
好吧,让我们稍微备份一下。
Haskell 中的“未定义”是“底部”值(表示为 ⊥)的一个示例。这样的值表示程序中任何未定义、卡住或部分状态。
存在许多不同形式的底层:非终止循环、异常、模式匹配失败——基本上是程序中在某种意义上未定义的任何状态。价值undefined :: a
是将程序置于未定义状态的值的典型示例。
undefined
本身并不是特别特别——它没有连接——你可以实现 Haskell 的undefined
使用任何底部产生的表达式。例如。这是一个有效的实现undefined
:
> undefined = undefined
或者立即退出(旧的Gofer编译器使用这个定义):
> undefined | False = undefined
底部的主要属性是,如果表达式计算结果为底部,则整个程序将计算为底部:程序处于未定义状态。
为什么你想要这样的值?好吧,在惰性语言中,您通常可以操作存储底部值的结构或函数,而程序本身并不位于底部。
例如。无限循环列表是完美的:
> let xs = [ let f = f in f
, let g n = g (n+1) in g 0
]
> :t xs
xs :: [t]
> length xs
2
我对列表中的元素无能为力:
> head xs
^CInterrupted.
这种对无限事物的操纵是 Haskell 如此有趣和富有表现力的部分原因。懒惰的结果是 Haskell 尤为关注的bottom
values.
然而,显然,底层的概念同样适用于 Java 或任何(非总体)语言。在 Java 中,有许多表达式可以产生“底部”值:
- 将引用与 null 进行比较(但请注意,不是
null
本身,这是明确定义的);
- 被零除;
- 越界异常;
- 无限循环等
您只是无法轻松地将一个底部替换为另一个底部,并且 Java 编译器不会对底部值进行太多推理。然而,这样的价值观是存在的。
总之,
- 解除引用a
null
Java 中的 value 是一种在 Java 中产生底部值的特定表达式;
- the
undefined
Haskell 中的 value 是一个通用的底部产生表达式,可以在 Haskell 中需要底部值的任何地方使用。
这就是他们的相似之处。
后记
至于问题null
本身:为什么它被认为是不好的形式?
- 首先,Java的
null
本质上相当于添加隐式Maybe a
每种类型a
在哈斯克尔.
- 解引用
null
相当于仅针对Just
case: f (Just a) = ... a ...
所以当传入的值为Nothing
(在哈斯克尔),或null
(在 Java 中),您的程序达到未定义状态。这很糟糕:你的程序崩溃了。
所以,通过添加null
to every类型,您刚刚使创建变得更加容易bottom
意外的值——类型不再对你有帮助。您的语言不再帮助您防止这种特定类型的错误,这很糟糕。
当然,其他底部值仍然存在:例外(例如undefined
) ,或无限循环。为每个函数添加新的可能的故障模式——取消引用null
——只是让编写崩溃的程序变得更容易。