Я столкнулся с изоморфизмом Карри-Ховарда относительно поздно в моей жизни программирования, и, возможно, это способствует тому, что я полностью им очарован. Это означает, что для каждой концепции программирования существует точный аналог в формальной логике, и наоборот. Вот "базовый" список таких аналогий, невдомек:
program/definition | proof
type/declaration | proposition
inhabited type | theorem/lemma
function | implication
function argument | hypothesis/antecedent
function result | conclusion/consequent
function application | modus ponens
recursion | induction
identity function | tautology
non-terminating function | absurdity/contradiction
tuple | conjunction (and)
disjoint union | disjunction (or) -- corrected by Antal S-Z
parametric polymorphism | universal quantification
Итак, на мой вопрос: каковы некоторые из наиболее интересных / неясных последствий этого изоморфизма? Я не логик, поэтому уверен, что этим списком я лишь поверхностно коснулся.
Например, вот некоторые понятия программирования, для которых я не знаю содержательных названий в логике:
currying | "((a & b) => c) iff (a => (b => c))"
scope | "known theory + hypotheses"
А вот несколько логических концепций, которые я не совсем понял в терминах программирования:
primitive type? | axiom
set of valid programs? | theory
Редактировать:
Вот еще несколько эквивалентностей, собранных из ответов:
function composition | syllogism -- from Apocalisp
continuation-passing | double negation -- from camccann
источник
goto | jumping to conclusions
Ответы:
Поскольку вы явно просили самые интересные и непонятные:
Вы можете расширить CH на множество интересных логик и формулировок логик, чтобы получить действительно широкий спектр соответствий. Здесь я попытался сосредоточиться на некоторых из наиболее интересных, а не на малоизвестных, а также на паре фундаментальных, которые еще не возникли.
РЕДАКТИРОВАТЬ: Ссылка, которую я рекомендую всем, кто хочет узнать больше о расширениях CH:
«Судебная реконструкция модальной логики» http://www.cs.cmu.edu/~fp/papers/mscs00.pdf - это отличное место для начала, потому что оно начинается с первых принципов, и большая часть из них нацелена на то, чтобы доступный для нелогиков / теоретиков языка. (Хотя я второй автор, поэтому я пристрастен.)
источник
Вы немного путаете насчет непреодолимости. Ложь представлена необитаемыми типами , которые по определению не могут быть бесконечными, потому что в первую очередь нет ничего такого, что нужно было бы оценить.
Непрерывность представляет собой противоречие - противоречивую логику. Непоследовательная логика, конечно, позволит вам доказать все , что угодно , в том числе и ложь.
Игнорируя несоответствия, системы типов обычно соответствуют интуиционистской логике и по необходимости являются конструктивистскими , что означает, что некоторые части классической логики не могут быть выражены напрямую, если вообще могут быть выражены. С другой стороны, это полезно, потому что если тип является допустимым конструктивным доказательством, то термин этого типа является средством конструирования того, что вы доказали существование .
Главная особенность конструктивистского духа состоит в том, что двойное отрицание не эквивалентно неотрицанию. Фактически, отрицание редко является примитивом в системе типов, поэтому вместо этого мы можем представить его как подразумевающую ложь, например,
not P
становитсяP -> Falsity
. Таким образом, двойное отрицание было бы функцией с типом(P -> Falsity) -> Falsity
, которая явно не эквивалентна чему-то просто типуP
.Однако в этом есть интересный поворот! В языке с параметрическим полиморфизмом переменные типа охватывают все возможные типы, включая необитаемые, так что полностью полиморфный тип, такой как
∀a. a
в некотором смысле, почти ложен. Так что, если мы напишем двойное почти отрицание с помощью полиморфизма? Мы получаем тип , который выглядит следующим образом :∀a. (P -> a) -> a
. Это что-то вроде типаP
? Действительно , просто примените его к функции идентичности.Но в чем смысл? Зачем писать такой шрифт? Означает ли это что- нибудь с точки зрения программирования? Что ж, вы можете думать об этом как о функции, которая где-то уже имеет что-то типа
P
и требует, чтобы вы дали ей функцию, которая принимаетP
в качестве аргумента, причем все это является полиморфным в конечном типе результата. В некотором смысле он представляет собой приостановленное вычисление , ожидающее выполнения остальных. В этом смысле эти приостановленные вычисления можно составлять вместе, передавать, вызывать и т. Д. Это должно показаться знакомым поклонникам некоторых языков, таких как Scheme или Ruby, потому что это означает, что двойное отрицание соответствует стилю передачи продолжения., и на самом деле тип, который я привел выше, является в точности продолжением монады в Haskell.источник
P -> Falsity
. Я понимаю, почему это работает (¬p ≡ p → ⊥), но не получил версию кода.P -> ⊥
должны быть заселены именно тогда, когдаP
нет, не так ли? Но разве эта функция не должна всегда быть обитаемой? Или возможно никогда, на самом деле, поскольку вы не можете вернуть экземпляр⊥
? Я не совсем понимаю, насколько это обусловлено. Что тут за интуиция?P -> Falsity
эквивалентнаP
ложной.f x = x
, которая была бы инстанциирована, если бы и только тогдаP = ⊥
, но она явно не была достаточно общей. Идея состоит в том, что для возврата типа без значения вам не нужно тело; но для того, чтобы функция была определяемой и полной, вам не нужны кейсы , и поэтому, еслиP
она необитаемая, все работает? Это немного шатко, но я думаю, что вижу это. Кажется, это довольно странно взаимодействует с моим определениемXor
типа… Надо подумать. Спасибо!Ваш график не совсем правильный; во многих случаях вы путаете типы с терминами.
[1] Логика функционального языка, полного по Тьюрингу, противоречива. Рекурсия не имеет соответствия в непротиворечивых теориях. В противоречивой логике / теории необоснованных доказательств вы могли бы назвать это правилом, которое вызывает несогласованность / несостоятельность.
[2] Опять же, это следствие полноты. Это было бы доказательством анти-теоремы, если бы логика была последовательной - а значит, ее не могло бы быть.
[3] Не существует в функциональных языках, так как они исключают логические особенности первого порядка: вся количественная оценка и параметризация выполняется по формулам. Если бы у вас были функции первого порядка, были бы и другие, чем
*
,* -> *
и т.д .; вид элементов области дискурса. Например, вFather(X,Y) :- Parent(X,Y), Male(X)
,X
иY
охватывают область дискурса (назовите этоDom
), иMale :: Dom -> *
.источник
источник
Мне очень нравится этот вопрос. Я не очень много знаю, но кое-что у меня есть (чему помогает статья в Википедии , в которой есть несколько изящных таблиц и тому подобное):
Я думаю, что типы суммы / типы объединения ( например
data Either a b = Left a | Right b
) эквивалентны инклюзивной дизъюнкции. И хотя я не очень хорошо знаком с Карри-Ховардом, я думаю, что это демонстрирует это. Рассмотрим следующую функцию:Если я правильно понимаю, тип говорит, что ( a ∧ b ) → ( a ★ b ), а определение говорит, что это правда, где ★ либо включающее, либо исключающее, либо, в зависимости от того, что
Either
представляет. ВыEither
представляете эксклюзивное или, ⊕; однако ( a ∧ b ) ↛ ( a ⊕ b ). Например, ⊤ ∧ ⊤ ≡ ⊤, но ⊤ ⊕ ⊥ ≡ ⊥ и ⊤ ↛ ⊥. Другими словами, если и a, и b верны, тогда гипотеза верна, но вывод неверен, и поэтому это предположение должно быть ложным. Однако ясно, что ( a ∧ b ) → ( a ∨ б ), поскольку если и a, и b истинны, то по крайней мере одно истинно. Таким образом, если размеченные союзы являются некоторой формой дизъюнкции, они должны быть инклюзивным разнообразием. Я думаю, что это является доказательством, но не стесняйтесь разубедить меня в этом мнении.Точно так же ваши определения тавтологии и абсурда как функции идентичности и функции без завершения, соответственно, немного ошибочны. Истинная формула представлена типом единицы измерения , который имеет только один элемент (
data ⊤ = ⊤
часто пишется по буквам()
и / илиUnit
в языках функционального программирования). В этом есть смысл: поскольку этот тип гарантированно обитаем, и поскольку существует только один возможный житель, это должно быть правдой. Функция идентичности просто представляет собой особую тавтологию, согласно которой a → a .Ваш комментарий о непрерывных функциях, в зависимости от того, что именно вы имели в виду, более неуместен. Карри-Ховард работает в системе типов, но незавершение в ней не кодируется. Согласно Википедии , работа с незавершением является проблемой, так как добавление его приводит к противоречивой логике ( например , я могу определить с
wrong :: a -> b
помощьюwrong x = wrong x
и, таким образом, «доказать», что a → b для любых a и b ). Если это то, что вы имели в виду под «абсурдом», то вы совершенно правы. Если вместо этого вы имели в виду ложное утверждение, то вместо этого вам нужен любой необитаемый тип, например, что-то определенноеdata ⊥
- то есть тип данных без возможности его создания. Это гарантирует, что у него вообще нет значений, и поэтому он должен быть необитаемым, что эквивалентно false. Я думаю, что вы, вероятно, также могли бы использоватьa -> b
, так как если мы запретим неразрывные функции, то это тоже необитаемо, но я не уверен на 100%.Википедия говорит, что аксиомы кодируются двумя разными способами, в зависимости от того, как вы интерпретируете Карри-Ховарда: либо в комбинаторах, либо в переменных. Я думаю, что представление комбинатора означает, что предоставленные нам примитивные функции кодируют то, что мы можем сказать по умолчанию (аналогично тому, как modus ponens является аксиомой, потому что приложение функции является примитивным). И я думаю, что представление переменных на самом деле может означать то же самое - комбинаторы, в конце концов, - это просто глобальные переменные, которые являются конкретными функциями. Что касается примитивных типов: если я правильно об этом думаю, то я думаю, что примитивные типы - это сущности - примитивные объекты, относительно которых мы пытаемся что-то доказать.
Согласно моему классу логики и семантики, тот факт, что ( a ∧ b ) → c ≡ a → ( b → c ) (а также, что b → ( a → c )) называется законом эквивалентности экспорта, по крайней мере, в естественном выводе доказательства. В то время я не заметил, что это просто карри - я бы хотел, потому что это круто!
Хотя теперь у нас есть способ представить инклюзивную дизъюнкцию, у нас нет способа представить исключительное разнообразие. Мы должны иметь возможность использовать определение исключительной дизъюнкции для ее представления: a ⊕ b ≡ ( a ∨ b ) ∧ ¬ ( a ∧ b ). Я не знаю, как писать отрицание, но я знаю, что ¬ p ≡ p → ⊥, и и импликация, и ложь - это легко. Таким образом, мы должны иметь возможность представить исключительную дизъюнкцию с помощью:
Это определяется
⊥
как пустой тип без значений, что соответствует ложности;Xor
Затем определяется , чтобы содержать оба ( и ) или б ( или ) и функцию ( Подразумевается ) из (а, б) ( а ) к нижнему типу ( ложной ).Однако я понятия не имею, что этозначит.( Правка 1: Теперь да, см. Следующий абзац!)Поскольку нет значений типа(есть ли?), Я не могу понять, что это будет означать в программе.Кто-нибудь знает, как лучше подумать об этом или другом определении?Either
( Редактировать 1: Да, camccann .)(a,b) -> ⊥
Изменить 1: Благодаря ответу camccann (в частности, комментариям, которые он оставил, чтобы помочь мне), я думаю, что вижу, что здесь происходит. Чтобы создать значение типа
Xor a b
, вам нужно предоставить две вещи. Во-первых, свидетельство существования элемента любогоa
илиb
в качестве первого аргумента; то есть aLeft a
или aRight b
. И во-вторых, доказательство того, что нет элементов обоих типов,a
иb
- другими словами, доказательство(a,b)
необитаемости - в качестве второго аргумента. Так как вы только будете в состоянии написать функцию из ,(a,b) -> ⊥
если(a,b)
необитаем, что это значит для того , чтобы быть дело? Это означало бы, что некоторая часть объекта типа(a,b)
не мог быть построен; другими словами, что , по меньшей мере , один, и , возможно , оба,a
иb
необитаемые , как хорошо! В этом случае, если мы думаем о сопоставлении с образцом, вы не могли бы найти сопоставление с образцом для такого кортежа: предположим, чтоb
он необитаемый, что бы мы написали, что могло бы соответствовать второй части этого кортежа? Таким образом, мы не можем сопоставить его с шаблоном, что может помочь вам понять, почему это делает его необитаемым. Теперь единственный способ иметь общую функцию, которая не принимает аргументов (как это и должно быть, поскольку(a,b)
она необитаема), - это сделать результат также необитаемого типа - если мы думаем об этом с точки зрения сопоставления с образцом, это означает, что даже если у функции нет случаев, нет возможного тела могло быть и то, и другое, так что все в порядке.Многое из этого я размышляю вслух / доказываю (надеюсь) на лету, но я надеюсь, что это полезно. Я очень рекомендую статью в Википедии ; Я не читал его подробно, но его таблицы - действительно хорошее резюме, и оно очень тщательное.
источник
Either a a
не должно быть теоремой:Either ⊥ ⊥
все еще необитаем. Том: Как сказал Камканн, последовательность подразумевает прекращение. Таким образом, согласованная система типов не позволит вам выразитьf :: a -> b
, и поэтому тип будет необитаемым; несовместимая система типов будет иметь обитателя для типа, но не завершится. camccann: Существуют ли несовместимые системы типов, которые не являются полными по Тьюрингу и занимают промежуточную точку в иерархии? Или этот последний шаг (добавление общей рекурсии или что-то еще) в точности эквивалентен несогласованности?Вот несколько непонятный вопрос, который, к моему удивлению, не упоминался ранее: «классическое» функциональное реактивное программирование соответствует временной логике.
Конечно, если вы не философ, математик или одержимый функциональным программистом, это, вероятно, поднимет еще несколько вопросов.
Итак, для начала: что такое функциональное реактивное программирование? Это декларативный способ работы со значениями, изменяющимися во времени . Это полезно для написания таких вещей, как пользовательские интерфейсы, потому что вводимые пользователем значения являются значениями, которые меняются со временем. «Классический» FRP имеет два основных типа данных: события и поведение.
События представляют собой значения, которые существуют только в дискретное время. Нажатие клавиш - отличный пример: вы можете думать о вводе с клавиатуры как о символе в данный момент. Каждое нажатие клавиши - это просто пара с символом клавиши и временем ее нажатия.
Поведение - это ценности, которые существуют постоянно, но могут постоянно меняться. Положение мыши - отличный пример: это просто поведение координат x, y. В конце концов, у мыши всегда есть позиция, и концептуально это положение постоянно изменяется при перемещении мыши. В конце концов, перемещение мыши - это единичное длительное действие, а не набор отдельных шагов.
А что такое темпоральная логика? Соответственно, это набор логических правил для работы с предложениями, количественно оцениваемыми с течением времени. По сути, он расширяет нормальную логику первого порядка двумя кванторами: □ и ◇. Первое означает «всегда»: читаем □ φ как «φ всегда выполняется». Второй - «в конце концов»: φ означает, что «в конечном итоге сохранится». Это особый вид модальной логики . Следующие два закона связывают кванторы:
Итак, □ и двойственны друг другу так же, как и ∃.
Эти два квантификатора соответствуют двум типам в FRP. В частности, □ соответствует поведению, а ◇ - событиям. Если мы подумаем о том, как эти типы заселены, это должно иметь смысл: поведение заселяется каждый возможный момент, а событие происходит только один раз.
источник
Связанный с отношениями между продолжениями и двойным отрицанием, тип call / cc - это закон Пирса http://en.wikipedia.org/wiki/Call-with-current-continuation
CH обычно утверждается как соответствие между интуиционистской логикой и программами. Однако, если мы добавим оператор call-with-current-continue (callCC) (тип которого соответствует закону Пирса), мы получим соответствие между классической логикой и программами с callCC.
источник
Хотя это не простой изоморфизм, обсуждение конструктивной LEM является очень интересным результатом. В частности, в заключительном разделе Олег Киселев обсуждает, как использование монад для получения исключения двойного отрицания в конструктивной логике аналогично различению вычислительно разрешимых суждений (для которых LEM действительна в конструктивном контексте) от всех суждений. Представление о том, что монады захватывают вычислительные эффекты, является старым, но этот пример изоморфизма Карри-Ховарда помогает представить его в перспективе и помогает понять, что на самом деле «означает» двойное отрицание.
источник
Первоклассная поддержка продолжений позволяет выразить $ P \ lor \ neg P $. Уловка основана на том факте, что отказ от вызова продолжения и выхода с каким-либо выражением эквивалентен вызову продолжения с тем же выражением.
Более подробную информацию см. На странице http://www.cs.cmu.edu/~rwh/courses/logic/www-old/handouts/callcc.pdf.
источник
Одна вещь, которая важна, но еще не исследована, - это взаимосвязь 2-продолжения (продолжения, которое принимает 2 параметра) и штриха Шеффера . В классической логике штрих Шеффера может сам по себе образовывать полную логическую систему (плюс некоторые неоператорные концепции). Это означает , знакомый
and
,or
,not
может быть реализована с использованием только топить Шеффер илиnand
.Это важный факт соответствия типов программирования, поскольку он подсказывает, что комбинатор одного типа может использоваться для формирования всех других типов.
Тип подписи 2-продолжение есть
(a,b) -> Void
. С помощью этой реализации мы можем определить 1-продолжение (нормальное продолжение) как(a,a)
-> Пустота, тип продукта как((a,b)->Void,(a,b)->Void)->Void
, тип суммы как((a,a)->Void,(b,b)->Void)->Void
. Это дает нам впечатляющую силу выразительности.Если копнуть дальше, мы обнаружим, что экзистенциальный граф Piece эквивалентен языку с единственным типом данных n-продолжение, но я не видел, чтобы какие-либо существующие языки были в этой форме. Думаю, изобрести его может быть интересно.
источник