В чем разница между неопределенным в Haskell и нулевым в Java?
Хорошо, давайте вернемся немного назад.
"undefined" в Haskell является примером "нижнего" значения (обозначается ⊥). Такое значение представляет любое неопределенное, застрявшее или частичное состояние в программе.
Существует множество различных форм дна: бесконечные циклы, исключения, сбои сопоставления с образцом - практически любое состояние в программе, которое в некотором смысле не определено. Значение undefined :: a
является каноническим примером значения, которое переводит программу в неопределенное состояние.
undefined
сам по себе не особенно особенный - он не подключен - и вы можете реализовать undefined
на Haskell, используя любое нижнее выражение. Например. это допустимая реализация undefined
:
> undefined = undefined
Или немедленно выйти (старый компилятор Gofer использовал это определение):
> undefined | False = undefined
Основным свойством bottom является то, что если выражение оценивается снизу, вся ваша программа будет вычислять снизу: программа находится в неопределенном состоянии.
Зачем вам такая ценность? Ну, на ленивом языке вы часто можете манипулировать структурами или функциями, которые хранят нижние значения, при этом сама программа не является нижней.
например. список бесконечных циклов совершенно сгущен:
> 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 уделяет особое внимание значениям bottom
.
Однако ясно, что концепция дна одинаково хорошо применима и к Java, или к любому (не тотальному) языку. В Java есть много выражений, которые выдают «нижние» значения:
- сравнение ссылки с нулем (хотя обратите внимание, но не
null
, что четко определено);
- деление на ноль;
- исключения за пределами;
- бесконечный цикл и т. Д.
У вас просто нет возможности очень легко заменить одно дно на другое, и компилятор Java мало что делает для обоснования значений дна. Однако такие значения есть.
В итоге
- разыменование значения
null
в Java - это одно конкретное выражение, которое возвращает нижнее значение в Java;
- значение
undefined
в Haskell - это универсальное нижнее выражение, которое можно использовать везде, где требуется нижнее значение в Haskell.
Вот так они похожи.
Постскриптум
Что касается самого вопроса null
: почему это считается дурным тоном?
- Во-первых, Java
null
по сути эквивалентен добавлению неявного Maybe a
к каждому типу a
в Haskell .
- Разыменование
null
эквивалентно сопоставлению с образцом только для случая Just
: f (Just a) = ... a ...
Таким образом, когда переданное значение равно Nothing
(в Haskell) или null
(в Java), ваша программа достигает неопределенного состояния. Это плохо: ваша программа вылетает.
Итак, добавив null
к каждому типу , вы просто упростили создание значений bottom
случайно - типы больше не помогают вам. Ваш язык больше не помогает вам предотвращать ошибки такого рода, и это плохо.
Конечно, все еще существуют другие нижние значения: исключения (например, undefined
) или бесконечные циклы. Добавление нового режима возможного сбоя к каждой функции - разыменование null
- просто облегчает написание программ, которые аварийно завершают работу.