Какова роль "нижней" (⊥) в определениях функций Haskell?
Я не понимаю роли bottom
(⊥
или _|_
) в определениях функций Haskell.
Определение zip
, например, описывает его как "правильное ленивое", потому что
zip [] _|_ = []
но я не понимаю, как это отличается от
zip [] _ = []
Какую роль играет _|_
в определении функций, например, выше? В частности, как это отличается от использования _
?
ОБНОВЛЕНИЕ И ЗАМЕЧАНИЕ: поскольку читатели превосходных ответов обнаружат для себя, важная часть этих ответов стоит здесь: ⊥
не (и не может), по сути, появляются в определениях функций Haskell. Читайте дальше.
Ответы
Ответ 1
Внизу, по сути, есть фантастический алгебраический способ сказать undefined
.
Если вы попробуете это, вы можете понять, почему zip
ленив за свой правый аргумент:
λ> zip [] undefined
[]
λ> zip undefined []
*** Exception: Prelude.undefined
Это связано с тем, что undefined
работает только при попытке оценить его.
Возможно, вы сбиваете с толку _|_
с помощью _
из-за того, как он был представлен. Я проясню: строка zip [] _|_ = []
не действует как совпадение с шаблоном, а уравнение, указывающее равенство zip [] _|_
и []
. То есть это недопустимый код Хаскелла, но нотационный, абстрактно-алгебраический способ сказать: "Меня не волнует второй аргумент".
В определении zip
вы можете, конечно, использовать _
, но это не имеет значения. Вы могли бы использовать любое имя, до тех пор, пока оно не соответствует шаблону соответствия конструктора, например (Just x)
или (a,b)
. Значения останутся неизменными до тех пор, пока они не будут соответствовать образцу в чистом коде.
Подробнее о ленивой оценке здесь.
Подробнее о нижнем здесь и здесь.
Ответ 2
Я думаю, что ОП уже осознает это, но на благо других, которые приходят сюда с такой же путаницей: zip [] _|_ = []
не является фактическим кодом!
Символ _|_
(который представляет собой только рендеринг математического символа ⊥
ascii-art) означает bottom 1 но только когда мы говорим о Haskell. В коде Haskell это значение не имеет значения 2.
Строка zip [] _|_ = []
представляет собой описание свойства фактического кода для zip
; что если вы вызываете его с первым аргументом []
и передаете любое нижнее значение в качестве второго аргумента, результат равен []
. Причина, по которой они хотели бы сказать именно это, состоит в том, что техническое определение того, что означает для функции f
быть нестрогим, - это когда f ⊥
не ⊥
.
Но при определении функций Haskell (в коде) нет роли _|_
(или ⊥
, или undefined
, или вообще концепции дна). Невозможно сопоставить шаблон по аргументу, чтобы определить, является ли он ⊥
по ряду причин, и поэтому в коде Haskell 3 нет фактического символа для ⊥
. zip [] _|_ = []
представляет собой документацию о свойстве, которое является следствием определения zip
, а не части его определения.
Как описание этого свойства zip [] _ = []
является менее конкретным требованием; он сказал бы, что чем бы вы не назовете zip []
on, он возвращает []
. Это то же самое, так как единственный способ zip [] ⊥
может вернуть что-то не дно, если он вообще не проверяет свой второй аргумент. Но это говорит не сразу о определении нестрогости.
Поскольку код, составляющий часть определения функции zip [] _ = []
, нельзя сравнивать и противопоставлять zip [] _|_ = []
. Они не альтернативы, первый - действительный код, а второй - нет.
1 Который является "значением" выражения, которое выполняется навсегда, выдает исключение или иным образом падает, чтобы оценить нормальное значение.
2 Это даже не действительный идентификатор Haskell, так как он содержит символы "namey" (_
) и "operator" (|
). Таким образом, это не может быть символом, означающим что-либо вообще в коде Haskell!
3undefined
часто используется для ⊥
, но это скорее переменная, относящаяся к значению ⊥
, чем сама фактическая вещь. Как и в случае с let xs = [1, 2, 3]
, вы можете использовать xs
для ссылки на список [1, 2, 3]
, но вы не можете использовать его в качестве шаблона для сопоставления некоторого другого списка; совпадение с запрограммированным шаблоном просто рассматривалось бы как введение новой переменной с именем undefined
или xs
затенением старой.
Ответ 3
⊥ вытекает из теории математического порядка. Частично упорядоченная коллекция имеет нижний элемент, обозначаемый ⊥, если этот элемент предшествует каждому другому элементу. Как это попадает в документацию Haskell? В какой-то момент компьютерные ученые поняли, что было бы полезно подумать о том, что означает компьютерная программа на любом языке. Один подход к этому называется денотационной семантикой. В денотационной семантике каждому термину на языке программирования присваивается "обозначение" или значение в некоторой вселенной математических значений. Было бы замечательно, если бы можно было сказать, что
-
meaningInteger :: Integer -> mathematical integer
-
meaningList :: [a] -> possibly-infinite sequence of elements of type a
К сожалению, это не совсем работает в Haskell, потому что, например, я могу написать
oops :: Integer
oops = oops
Это дает мне термин типа Integer
, но нет разумного способа присвоить ему значение как математическое целое. Более интересно, я мог писать такие вещи, как
undefined
undefined : undefined
3 : undefined
[undefined]
let foo = undefined : 3 : undefined : foo
Эти все (могут) имеют один и тот же тип, но имеют разные уровни неопределенности. Поэтому нам нужно добавить в нашу коллекцию значений различные виды undefined вещей. Однако возможно наложить на них частичный порядок в зависимости от того, как они определены! Например, 3 : 4 : []
более определен, чем 3 : 4 : undefined
, а также более определен, чем 3 : undefined : 4
, но последние два не сопоставимы. Нижний элемент каждого типа, его наименее определенный элемент, называется ⊥.
Ответ 4
Riffing на AJFarmar ответе, я думаю, что эта критическая точка не была сделана явной:
-
_|_
не является допустимым литералом или идентификатором в коде Haskell!
- И поэтому
zip [] _|_ = []
также не является допустимым кодом!
Это подразумевается в том, что AJFarmar означает по этой цитате:
[T] he line zip [] _|_ = []
не действует как совпадение шаблона, а уравнение, указывающее равенство zip [] _|_
и []
.
Чтобы сделать его очень четким, zip [] _|_ = []
отображается в комментариях документации для определения zip
. Это не код Haskell - это комментарий на английском языке, написанный в неофициальной технической нотации, которая немного похожа на код Haskell. Или, другими словами, псевдокод.