Подтвердить что ты не робот

Какая разница между undefined в Haskell и null в Java?

Оба являются терминами, тип которых является пересечением всех типов (необжитых). Оба могут быть переданы в коде без сбоев, пока вы не попытаетесь их оценить. Единственное отличие, которое я вижу, это то, что в Java есть лазейка, которая позволяет оценивать null для одной операции, которая является сравнительным сравнением равенства (==), тогда как в Haskell undefined не может быть оценивается вообще, не вызывая исключения. Разве это единственная разница?

Изменить

То, что я действительно пытаюсь решить с этим вопросом, заключается в том, почему в Java было такое null такое явно плохое решение, и как Haskell избегает его? Мне кажется, что реальная проблема заключается в том, что вы можете сделать что-то полезное с помощью null, а именно, вы можете проверить его на nullness. Поскольку вам разрешено это делать, стало стандартным соглашением обходить нулевые значения в коде и указать им "нет результата" вместо "в этой программе есть логическая ошибка". Принимая во внимание, что в Haskell нет способа проверить, оценивает ли термин дно, не оценивая его и взрыва программы, поэтому он никогда не может использоваться таким образом, чтобы указывать "нет результата". Вместо этого один вынужден использовать что-то вроде Maybe.

Извините, если мне кажется, что я играю быстро и свободно с термином "оценивать"... Я пытаюсь провести здесь аналогию и нечаянно сформулировать его. Я предполагаю, что признак того, что аналогия неточна.

4b9b3361

Ответ 1

Какая разница между undefined в Haskell и null в Java?

Хорошо, немного поднимитесь.

"undefined" в Haskell является примером "нижнего" значения (обозначается ⊥). Такое значение представляет любое undefined, застрявшее или частичное состояние в программе.

Существует множество различных форм дна: неконцевые циклы, исключения, неудачи совпадения шаблонов - в основном любое состояние в программе, которое undefined в некотором смысле. Значение undefined :: a является каноническим примером значения, которое ставит программу в состояние undefined.

undefined сам по себе не особенно особенный - его не подключен к сети, и вы можете реализовать Haskell undefined, используя любое нижестоящее выражение. Например. это допустимая реализация undefined:

 > undefined = undefined

Или немедленно выйти (старый компилятор Gofer использовал это определение):

 > undefined | False = undefined

Основное свойство дна состоит в том, что если выражение оценивается снизу, вся ваша программа будет оцениваться снизу: программа находится в состоянии 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 уделяет особенно пристальное внимание значениям bottom.

Однако, очевидно, концепция дна одинаково хорошо применима к Java или к любому (неточному) языку. В Java существует много выражений, которые дают "нижние" значения:

  • сравнение ссылки с нулевым (хотя примечание, а не null, которое хорошо определено);
  • деление на ноль;
  • исключения из-за границ;
  • бесконечный цикл и т.д.

У вас просто нет возможности подставить одно дно для другого очень легко, а компилятор Java не очень-то разбирается в нижних значениях. Однако такие значения есть.

Таким образом,

  • разыменование значения null в Java - это одно конкретное выражение, которое дает нижнее значение в Java;
  • Значение undefined в Haskell - это общее генерирующее нижние выражения, которое может использоваться везде, где требуется значение нижнего значения в Haskell.

Как они похожи.

Postscript

Что касается самого вопроса null: почему он считается плохим?

  • Во-первых, Java null по существу эквивалентен добавлению неявного Maybe a к каждому типу a в Haskell.
  • Выделение null эквивалентно сопоставлению с образцом только для случая Just: f (Just a) = ... a ...

Итак, когда переданное значение равно Nothing (в Haskell) или null (в Java), ваша программа достигает состояния undefined. Это плохо: ваша программа вылетает.

Итак, добавив null к каждому типу, вам просто стало легче создавать значения bottom случайно - типы больше не помогают вам. Ваш язык больше не помогает вам предотвращать подобную ошибку, и это плохо.

Конечно, другие нижние значения все еще существуют: исключения (например, undefined) или бесконечные петли. Добавление нового возможного режима отказа к каждой функции - разыменование null - просто упрощает запись аварийных программ.

Ответ 2

Ваше описание не совсем корректно. Вы говорите, что null невозможно оценить. Однако, поскольку java является нетерпеливым языком, это означает, что f(null) будет вызывать NPE независимо от того, что такое определение f (поскольку аргументы метода всегда оцениваются до запуска метода).

Единственная причина, по которой вы можете обойти undefined в haskell без получения исключения, это то, что haskell ленив и не оценивает аргументы, если это не требуется.

Еще одно различие между undefined и null заключается в том, что undefined - это простое значение, определенное в стандартной библиотеке. Если он не был определен в стандартной библиотеке, вы могли бы определить его самостоятельно (например, написав myUndefined = error "My Undefined).

В Java null есть ключевое слово. Если ключевое слово null не было, вы бы не смогли его определить (выполнение эквивалента определения haskell, т.е. Object myNull = throw(new Exception()), не будет работать, потому что выражение будет оцениваться именно там).