Одним из определяющих свойств или пустого типа является то , что существует функция для каждого типа . На самом деле, существует уникальная такая функция. Поэтому вполне разумно, чтобы эта функция предоставлялась как часть стандартной библиотеки. Часто это называется что-то вроде . (В системах с подтипами это может быть выполнено просто при наличии как подтипа каждого типа. Тогда подразумевается неявное преобразование . Другой связанный подход заключается в определении как который может быть просто создан для любой тип.)⊥⊥ → AA⊥ ⊥ ∀ α . αabsurd
⊥absurd
⊥∀α.α
Вы определенно хотите иметь такую функцию или эквивалент, потому что это то, что позволяет вам использовать функции, которые производят . Например, предположим, что я дал тип сумму . Я делаю анализ случая и в случае я собираюсь исключение, используя . В случае, я буду использовать . В целом, я хочу значение типа , так что мне нужно сделать что - то , чтобы превратить в . Это то, что позволило бы мне сделать.⊥E+AEthrow:E→⊥Af:A→BB⊥Babsurd
Тем не менее, есть не много причин , чтобы определить свои собственные функции . По определению они обязательно будут экземплярами . Тем не менее, вы можете сделать это, если это не предусмотрено стандартной библиотекой, или вам нужна специализированная версия типа, чтобы помочь проверке / выводу типа. Вы можете, однако, легко производить функции , которые в конечном итоге инстанцирован к типу как .⊥→A⊥ → Aabsurd
absurd
⊥→A
Хотя для написания такой функции нет особых оснований, ее, как правило, следует разрешить . Одна из причин заключается в том, что это упрощает инструменты генерации кода / макросы.
Дерек Элкинс покинул ЮВ
источник
(x ? 3 : throw new Exception())
заменяется в целях анализа чем-то более похожим(x ? 3 : absurd(throw new Exception()))
?absurd
absurd
throw
Чтобы добавить к тому, что было сказано о функции, у
absurd: ⊥ -> a
меня есть конкретный пример того, где эта функция действительно полезна.Рассмотрим тип данных Haskell,
Free f a
который представляет общую древовидную структуру сf
узлами -образной формы и листьями, содержащимиa
s:data Free f a = Op (f (Free f a)) | Var a
Эти деревья можно сложить с помощью следующей функции:
Вкратце, эта операция размещается
alg
в узлах иgen
на листьях.Теперь к сути: все рекурсивные структуры данных могут быть представлены с использованием типа данных с фиксированной точкой. В Haskell это есть
Fix f
и может быть определено какtype Fix f = Free f ⊥
(то есть деревья сf
узлами -образной формы и без листьев вне функтораf
). Традиционно эта структура также имеет складку, называемуюcata
:Что дает довольно аккуратное использование абсурда: поскольку у дерева не может быть никаких листьев (поскольку у ⊥ нет других жителей, кроме
undefined
), никогда не возможно использоватьgen
для этого сгиба иabsurd
иллюстрирует это!источник
Тип bottom - это подтип любого другого типа, который может быть чрезвычайно полезен на практике. Например, тип
NULL
в теоретической типобезопасной версии C должен быть подтипом любого другого типа указателя, в противном случае вы не сможете, например, вернуть,NULL
гдеchar*
ожидалось a ; аналогично, типundefined
в теоретически безопасном типе JavaScript должен быть подтипом любого другого типа в языке.В качестве возвращаемого типа функции также очень полезно иметь определенные функции, которые никогда не возвращаются. Например, в строго типизированном языке с исключениями, какой тип должен⊥
exit()
или долженthrow()
возвращаться? Они никогда не возвращают поток управления своему абоненту. А поскольку нижний тип является подтипом любого другого типа, он вполне подходит для функции, возвращающейInt
вместо return то есть возвращающая функция также может вообще не возвращать. (Может быть, он вызывает , или, может быть, он входит в бесконечный цикл.) Это хорошо иметь, потому что ли функция когда-либо возвращается или нет, классно неразрешима.Int
exit()
Наконец, это очень полезно для написания ограничений. Предположим, вы хотите ограничить все параметры на «обеих сторонах», предоставив тип, который должен быть супертипом параметра, и другой тип, который должен быть подтипом. Поскольку дно подтип любого типа, вы можете выразить «любой подтип S» как . Или вы можете выразить «любой тип вообще» как .⊥≺T≺S ⊥≺T≺⊤
источник
NULL
это тип единицы, не так ли, в отличие от ⊥, который является пустым типом?void*
, вам нужен определенный тип для него, который можно использовать для любого типа указателя.<:
например, SystemЯ могу придумать одно применение, и это то, что считается улучшением языка программирования Swift.
Свифт имеет
maybe
монаду, пишетсяOptional<T>
илиT?
. Есть много способов взаимодействия с ним.Вы можете использовать условное развертывание как
Вы можете использовать
map
,flatMap
чтобы преобразовать значения!
типа(T?) -> T
) для принудительного развертывания содержимого, в противном случае происходит сбойОператор nil-coalescing (
??
, типа(T?, T) -> T
) принимает свое значение или иным образом использует значение по умолчанию:К сожалению, не было краткого способа сказать «развернуть или выбросить ошибку» или «развернуть или аварийно завершить работу с пользовательским сообщением об ошибке». Что-то вроде
не компилируется, потому что
fatalError
имеет тип() -> Never
(()
естьVoid
, типNever
устройства Swift, это нижний тип Swift). Вызов его производитNever
, что несовместимо сT
ожидаемым в качестве правильного операнда??
.В попытке исправить это, был предложен продукт Swift Evolution
SE-0217
- оператор «Развернуть или умереть» . Это было в конечном счете отклонено , но это подняло интерес к тому, чтобыNever
быть подтипом всех типов.Если
Never
задан подтип всех типов, предыдущий пример будет компилируемым:потому что сайт вызова
??
имеет тип(T?, Never) -> T
, который будет совместим с(T?, T) -> T
подписью??
.источник
Swift имеет тип «Никогда», который, похоже, очень похож на нижний тип: функция, объявленная для возврата «Никогда», никогда не сможет вернуться, функция с параметром типа «Никогда» никогда не может быть вызвана.
Это полезно в связи с протоколами, где может существовать ограничение из-за системы типов языка, что класс должен иметь определенную функцию, но без требования, чтобы эта функция когда-либо вызывалась, и без требования, что типы аргумента было бы.
Для получения подробной информации вы должны взглянуть на новые сообщения в списке рассылки swift-evolution.
источник