В чем разница между undefined в Haskell и null в Java?
Вопрос
Оба термина, тип которых является пересечением всех типов (необитаемый).Оба варианта могут передаваться в коде без сбоев до тех пор, пока кто-то не попытается их оценить.Единственное отличие, которое я вижу, заключается в том, что в Java есть лазейка, которая позволяет null
должен быть оценен ровно для одной операции, которая является сравнением равенства ссылок (==
) - тогда как в Haskell undefined
вообще не может быть оценено без создания исключения.Это единственное отличие?
Редактировать
Чего я действительно пытаюсь добиться с помощью этого вопроса, так это того, почему было включено null
в Java такое явно неудачное решение, и как Haskell избегает его?Мне кажется, настоящая проблема в том, что вы можете что-то сделать полезный с null
, а именно вы можете проверить это на ничтожность.Поскольку вам разрешено это делать, стало стандартным соглашением передавать нулевые значения в коде и указывать на них "нет результата" вместо "в этой программе логическая ошибка".Принимая во внимание, что в Haskell нет способа проверить, достигает ли значение term значения bottom, без его оценки и сбоя программы, поэтому его никогда нельзя было использовать таким образом, чтобы указать "нет результата".Вместо этого человек вынужден использовать что-то вроде Maybe
.
Извините, если вам кажется, что я слишком поспешно использую термин "оценивать"...Я пытаюсь провести здесь аналогию, но мне трудно точно ее сформулировать.Я думаю, это признак того, что аналогия неточна.
Решение
В чем разница между undefined в Haskell и null в Java?
Хорошо, давайте немного вернемся назад.
"undefined" в Haskell является примером "нижнего" значения (обозначается ⊥).Такое значение представляет любое неопределенное, зависшее или частичное состояние в программе.
Существует много различных форм дна:не завершающиеся циклы, исключения, сбои сопоставления с шаблоном - в принципе, любое состояние в программе, которое в некотором смысле не определено.Значение undefined :: a
является каноническим примером значения, которое переводит программу в неопределенное состояние.
undefined
сам по себе не является чем-то особенным - он не подключен - и вы можете реализовать Haskell's undefined
используя любое низкопродуктивное выражение.Например.это допустимая реализация undefined
:
> undefined = undefined
Или выходящий немедленно (старый компилятор Gofer использовал это определение):
> undefined | False = undefined
Основным свойством bottom является то, что если выражение принимает значение bottom, то вся ваша программа примет значение 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 такой веселый и выразительный.Результатом лени является то, что Haskell уделяет особенно пристальное внимание bottom
ценности.
Однако очевидно, что концепция bottom одинаково хорошо применима к Java или любому другому (не тотальному) языку.В Java существует множество выражений, которые выдают "нижние" значения:
- сравнение ссылки с null (хотя, заметьте, не
null
сам по себе, который четко определен); - деление на ноль;
- исключения, выходящие за рамки;
- бесконечный цикл и т.д.
У вас просто нет возможности очень легко заменить одно дно на другое, а компилятор Java мало что делает для рассуждений о нижних значениях.Однако такие ценности существуют.
Подводя итог,
- разыменование a
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
-- просто упрощает написание программ, которые выходят из строя.
Другие советы
Ваше описание не совсем правильно. Вы говорите null
не может быть оценено. Однако, поскольку Java - это нетерпеливый язык, это будет означать, что f(null)
бросил бы НПУ, независимо от того, какое определение f
Есть (потому что аргументы метода всегда оцениваются до прогонов метода).
Единственная причина, по которой вы можете пройти undefined
В Haskell без получения исключения заключается в том, что Haskell ленивый и не оценивает аргументы, если не требуется.
Еще одна разница между неопределенным и нулевым является то, что undefined
это простое значение, определенное в стандартной библиотеке. Если он не определен в стандартной библиотеке, вы можете определить это самостоятельно (написав myUndefined = error "My Undefined
Например).
В Ява null
это ключевое слово. Если бы не было null
Ключевое слово, вы не сможете его определить (делает эквивалент определения Haskell, т. Е. Object myNull = throw(new Exception())
, не будет работать, потому что выражение будет оценено прямо там).