Ответ 1
Автор статьи "Политизм левитации".
Во-первых, я хочу прояснить несколько заблуждений, изложенных выше:
-
Bool
действительно поднят, в коробке. Однако он все еще имеет только 2 значения:True
иFalse
. Выражение ⊥ просто не является значением. Это выражение, и переменная может быть привязана к ⊥, но это не делает ⊥ значение. Возможно, лучший способ сказать все это в том, что еслиx :: Bool
, то оценкаx
может привести к трем различным результатам: оценкаTrue
, оценкаFalse
и ⊥. Здесь ⊥ представляет собой любое вычисление, которое не прекращается, как правило, в том числе метательного исключение (чтоundefined
действительно) и зацикливания. -
Подобно этой последней точке,
undefined
не является значением. Это житель любого типа, но это не значение. Значение - это то, что при оценке ничего не делает, ноundefined
не соответствует этой спецификации. -
В зависимости от того, как вы смотрите на него, ⊥ может существовать в нераскрытом типе. Например, возьмите это определение:
loop :: () -> Int# loop x = loop x
Это определение принимается GHC. Тем не менее
loop()
является элементом of неперекрытого, unboxed типаInt#
. Разница между непринятым типом и поднятым типом в этом отношении заключается в том, что невозможно привязать переменную кloop()
. Любая попытка сделать это (например,let z = loop() in...
) будет зацикливаться до того, как переменная будет привязана.Обратите внимание, что это не отличается от бесконечно рекурсивной функции в неуправляемом языке, например C.
Итак, как мы разрешаем undefined
иметь несдержанный тип? @dfeuer имеет это право: undefined
тайно функция. Его полная подпись типа не undefined :: forall (r :: RuntimeRep) (a :: TYPE r). HasCallStack => a
undefined :: forall (r :: RuntimeRep) (a :: TYPE r). HasCallStack => a
, что означает, что это функция, как и loop
, выше. Во время выполнения он будет принимать текущий стек вызовов в качестве параметра. Таким образом, всякий раз, когда вы используете undefined
, вы просто вызываете функцию, которая генерирует исключение, не создавая никаких проблем.
Действительно, при разработке полиморфизма легкомыслия, мы долгое время боролись с undefined
, со всеми видами махинаций, чтобы заставить его работать. Затем, когда мы поняли, что undefined
имеет ограничение HasCallStack
, мы увидели, что мы можем просто полностью уклониться от этой проблемы. Я, честно говоря, не знаю, что бы мы сделали без кажущегося несущественного удобства пользователей HasCallStack
.