absurd
Функция Data.Void
имеет следующую подпись, где Void
является логически необитаемым типом экспортируемого этого пакетом:
-- | Since 'Void' values logically don't exist, this witnesses the logical
-- reasoning tool of \"ex falso quodlibet\".
absurd :: Void -> a
Я знаю достаточно логики, чтобы получить из документации замечание о том, что это соответствует действительной формуле посредством соответствия предложений как типов ⊥ → a
.
Что меня озадачивает и интересует: в каких практических задачах программирования полезна эта функция? Я думаю, что, возможно, в некоторых случаях это полезно как типобезопасный способ исчерпывающей обработки случаев, когда «не может произойти», но я недостаточно знаю о практическом использовании Карри-Ховарда, чтобы сказать, есть ли эта идея на правильный трек вообще.
РЕДАКТИРОВАТЬ: Примеры желательно на Haskell, но если кто-то хочет использовать язык с зависимой типизацией, я не собираюсь жаловаться ...
источник
absurd
функция использовалась в этой статье, посвященнойCont
монаде: haskellforall.com/2012/12/the-continuation-monad.htmlabsurd
одно направление изоморфизма междуVoid
иforall a. a
.Ответы:
Жизнь немного трудна, поскольку Haskell не строг. Общий вариант использования - обработка невозможных путей. Например
Это оказывается несколько полезным. Рассмотрим простой тип для
Pipes
это строгая и упрощенная версия стандартного типа pipe из
Pipes
библиотеки Габриэля Гонсалеса . Теперь мы можем закодировать канал, который никогда не уступает (т. Е. Потребитель), какэто действительно никогда не поддается. Из этого следует, что правильным правилом складывания для a
Consumer
являетсяили, в качестве альтернативы, вы можете игнорировать вариант yield при работе с потребителями. Это общая версия этого шаблона проектирования: используйте полиморфные типы данных и
Void
избавьтесь от возможностей, когда вам это нужно.Вероятно, наиболее классическое использование
Void
- в CPS.то есть
Continuation
функция, которая никогда не возвращается.Continuation
это типовая версия «не». Отсюда получаем монаду CPS (соответствующую классической логике)поскольку Haskell чист, мы ничего не можем получить от этого типа.
источник
Void
необитаем. В Haskell он содержит_|_
. На строгом языке конструктор данных, который принимает аргумент типа,Void
никогда не может быть применен, поэтому правая часть сопоставления с образцом недоступна. В Haskell вам нужно использовать a!
для обеспечения этого, и GHC, вероятно, не заметит, что путь недоступен._|_
ли? и страдает ли он тогда тем же ограничением?Рассмотрим это представление для лямбда-членов, параметризованных их свободными переменными. (См. Статьи Беллегарда и Хука, 1994 г., Берд и Патерсон, 1999 г., Альтенкирх и Ройс, 1999 г.)
Вы, безусловно, можете сделать это a
Functor
, улавливая понятие переименования иMonad
улавливая понятие подстановки.Теперь рассмотрим закрытые условия: это жители
Tm Void
. Вы должны уметь вставлять закрытые термины в термины с произвольными свободными переменными. Как?Уловка, конечно же, в том, что эта функция будет проходить через термин, ничего не делая. Но это чуть более честно
unsafeCoerce
. И поэтомуvacuous
был добавлен вData.Void
...Или напишите оценщику. Вот значения со свободными переменными в
b
.Я только что представил лямбды как замыкания. Оценщик параметризуется средой, отображающей свободные переменные в
a
значениях сверхb
.Ты угадал. Оценить закрытый срок по любой цели
В более общем смысле,
Void
редко используется сам по себе, но он удобен, когда вы хотите создать экземпляр параметра типа способом, который указывает на какую-то невозможность (например, здесь, используя свободную переменную в закрытом члене). Часто эти параметризованные типы поставляются с функциями высшего порядка подъемных операций по параметрам операций по всему типу (например, здесь,fmap
,>>=
,eval
). Так что вы проходитеabsurd
как универсальную операцию по бэкапуVoid
.В качестве другого примера представьте, что вы используете
Either e v
для захвата вычислений, которые, надеюсь, дадут вам,v
но могут вызвать исключение типаe
. Вы можете использовать этот подход для единообразного документирования риска плохого поведения. Для прекрасно себя вычисления в этой обстановке, принять ,e
чтобы бытьVoid
, а затем использоватьбезопасно бежать или
внедрять безопасные компоненты в небезопасный мир.
О, и последнее ура, обработка «не может случиться». Он проявляется в общей конструкции застежки-молнии везде, где не может быть курсор.
Остальное решил не удалять, хоть это и не совсем актуально.
Собственно, может быть, это актуально. Если вы любите приключения, в этой незаконченной статье показано, как использовать
Void
для сжатия представления терминов с помощью свободных переменных.в любом синтаксисе свободно генерируется из
Differentiable
иTraversable
функтораf
. Мы используемTerm f Void
для представления областей без свободных переменных и[D f (Term f Void)]
для представления трубок, туннелирующих через области без свободных переменных либо к изолированной свободной переменной, либо к стыку на путях к двум или более свободным переменным. Надо когда-нибудь закончить эту статью.Для типа без значений (или, по крайней мере, такого, о котором стоит говорить в вежливой компании),
Void
это замечательно полезно. Иabsurd
как вы это используете.источник
forall f. vacuous f = unsafeCoerce f
ли действующее правило перезаписи GHC?Functor
экземпляры могут быть GADT, которые на самом деле не похожи на функторы.Functor
не нарушитfmap id = id
правило? Или это то, что вы здесь подразумеваете под «фальшивкой»?Это совершенно верно.
Можно сказать, что
absurd
это не более полезно, чемconst (error "Impossible")
. Однако он ограничен типом, так что его единственный вход может быть чем-то вроде типаVoid
, типом данных, который намеренно оставлен необитаемым. Это означает, что нет фактического значения, к которому вы можете перейтиabsurd
. Если вы когда-нибудь попадете в ветвь кода, где средство проверки типов думает, что у вас есть доступ к чему-то типуVoid
, то, что ж, вы попали в абсурдную ситуацию. Таким образом, вы просто используете,absurd
чтобы в основном отметить, что эта ветвь кода никогда не должна быть достигнута.«Ex falso quodlibet» буквально означает «из ложного [предложения] следует все, что угодно». Поэтому, когда вы обнаруживаете, что
Void
храните данные, тип которых является , вы знаете, что у вас на руках ложные доказательства. Таким образом, вы можете заполнить любую дыру, какую захотите (черезabsurd
), потому что из ложного предложения следует все, что угодно.Я написал сообщение в блоге об идеях, лежащих в основе Conduit, в котором есть пример использования
absurd
.http://unknownparallel.wordpress.com/2012/07/30/pipes-to-conduits-part-6-leftovers/#running-a-pipeline
источник
Как правило, вы можете использовать его, чтобы избежать частичных совпадений с образцом. Например, получение приблизительного объявления типов данных из этого ответа :
Тогда вы могли бы использовать
absurd
, например, вот так:источник
Есть разные способы представления пустого типа данных . Один из них - это пустой алгебраический тип данных. Другой способ - сделать его псевдонимом для ∀α.α или
в Haskell - вот как мы можем закодировать его в Системе F (см. главу 11 Доказательств и типов ). Эти два описания, конечно , изоморфны и изоморфизм засвидетельствовано
\x -> x :: (forall a.a) -> Void
иabsurd :: Void -> a
.В некоторых случаях мы предпочитаем явный вариант, обычно если пустой тип данных появляется в аргументе функции или в более сложном типе данных, например в Data.Conduit :
В некоторых случаях мы предпочитаем полиморфный вариант, обычно пустой тип данных участвует в возвращаемом типе функции.
absurd
возникает, когда мы конвертируем эти два представления.Например,
callcc :: ((a -> m b) -> m a) -> m a
использует (неявно)forall b
. Это также может быть тип((a -> m Void) -> m a) -> m a
, потому что вызов продолжения на самом деле не возвращает, он передает управление другой точке. Если бы мы хотели работать с продолжениями, мы могли бы определить(Мы могли бы использовать,
type Continuation' r a = forall b . a -> Cont r b
но для этого потребовались бы типы ранга 2.) А затемvacuousM
конвертирует этоCont r Void
вCont r b
.(Также обратите внимание, что вы можете использовать haskellers.com для поиска использования (обратных зависимостей) определенного пакета, например, чтобы узнать, кто и как использует пакет void .)
источник
TypeApplications
может быть использовано , чтобы быть более четко о деталяхproof :: (forall a. a) -> Void
:proof fls = fls @Void
.В языках с зависимой типизацией, таких как Idris, это, вероятно, более полезно, чем в Haskell. Как правило, в итоговой функции при сопоставлении с шаблоном значения, которое на самом деле нельзя вставить в функцию, вы затем создаете значение необитаемого типа и используете его
absurd
для завершения определения case.Например, эта функция удаляет элемент из списка с ограничением уровня типа, которое он там присутствует:
Во втором случае говорится, что в пустом списке есть определенный элемент, что является абсурдом. Однако в целом компилятор этого не знает, и нам часто приходится указывать это явно. Затем компилятор может проверить, что определение функции не является частичным, и мы получим более надежные гарантии времени компиляции.
С точки зрения Карри-Ховарда, где утверждения,
absurd
это своего рода КЭД в доказательстве от противного.источник