Какие самые интересные эквивалентности возникают из изоморфизма Карри-Ховарда?

98

Я столкнулся с изоморфизмом Карри-Ховарда относительно поздно в моей жизни программирования, и, возможно, это способствует тому, что я полностью им очарован. Это означает, что для каждой концепции программирования существует точный аналог в формальной логике, и наоборот. Вот "базовый" список таких аналогий, невдомек:

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
Том Крокетт
источник
закрытие ~ = набор аксиом
Apocalisp
+1 Этот вопрос, а также все качественные ответы и комментарии научили меня больше о ОМС, чем то, что я мог узнать через Интернет.
Alexandre C.
25
@Paul Nathan:goto | jumping to conclusions
Джои Адамс
Думаю, набор всех действующих программ был бы образцом
Даниил
1
fst / snd | исключение соединения, слева / справа | введение дизъюнкции
Тони Моррис

Ответы:

34

Поскольку вы явно просили самые интересные и непонятные:

Вы можете расширить CH на множество интересных логик и формулировок логик, чтобы получить действительно широкий спектр соответствий. Здесь я попытался сосредоточиться на некоторых из наиболее интересных, а не на малоизвестных, а также на паре фундаментальных, которые еще не возникли.

evaluation             | proof normalisation/cut-elimination
variable               | assumption
S K combinators        | axiomatic formulation of logic   
pattern matching       | left-sequent rules 
subtyping              | implicit entailment (not reflected in expressions)
intersection types     | implicit conjunction
union types            | implicit disjunction
open code              | temporal next
closed code            | necessity
effects                | possibility
reachable state        | possible world
monadic metalanguage   | lax logic
non-termination        | truth in an unobservable possible world
distributed programs   | modal logic S5/Hybrid logic
meta variables         | modal assumptions
explicit substitutions | contextual modal necessity
pi-calculus            | linear logic

РЕДАКТИРОВАТЬ: Ссылка, которую я рекомендую всем, кто хочет узнать больше о расширениях CH:

«Судебная реконструкция модальной логики» http://www.cs.cmu.edu/~fp/papers/mscs00.pdf - это отличное место для начала, потому что оно начинается с первых принципов, и большая часть из них нацелена на то, чтобы доступный для нелогиков / теоретиков языка. (Хотя я второй автор, поэтому я пристрастен.)

RD1
источник
спасибо, что предоставили несколько менее тривиальных примеров (это действительно было духом исходного вопроса), хотя я признаю, что некоторые из них неуместны ... точно ли термины «необходимость» и «возможность» определены в логике? как они переводятся в их вычислительные эквиваленты?
Tom Crockett
2
Я могу указать на опубликованные статьи по каждому из них, так что они точно определены. Модальная логика хорошо изучена (со времен Аристотеля) и связывает различные способы истины - «A обязательно истинно» означает «во всех возможных мирах A истинно», в то время как «A возможно истинно» означает «A истинно в одном возможном мире» . Вы можете доказать такие вещи, как «(обязательно (A -> B) и, возможно, A) -> возможно B». Правила модального вывода напрямую определяют конструкции выражений, правила набора и сокращения, как обычно в CH. См .: en.wikipedia.org/wiki/Modal_logic и cs.cmu.edu/~fp/papers/mscs00.pdf
RD1,
2
@pelotom: Возможно, вы захотите прочитать немного о других видах логики . Обычная классическая логика часто бесполезна в этом контексте - я упомянул интуиционистскую логику в своем ответе, но модальная и линейная логика еще «страннее», но также действительно потрясающе.
CA McCann
1
Спасибо за указатели, похоже, мне нужно кое-что почитать!
Tom Crockett
2
@ RD1: Ты думаешь, что это плохо, я столько времени думал на Haskell, что мне нужно мысленно переводить формулы логики предикатов в сигнатуры типов, прежде чем они обретут смысл. :( Не говоря уже о том, что закон исключенного третьего и тому подобное начинает казаться действительно запутанным и, возможно, подозрительным.
CA McCann
26

Вы немного путаете насчет непреодолимости. Ложь представлена необитаемыми типами , которые по определению не могут быть бесконечными, потому что в первую очередь нет ничего такого, что нужно было бы оценить.

Непрерывность представляет собой противоречие - противоречивую логику. Непоследовательная логика, конечно, позволит вам доказать все , что угодно , в том числе и ложь.

Игнорируя несоответствия, системы типов обычно соответствуют интуиционистской логике и по необходимости являются конструктивистскими , что означает, что некоторые части классической логики не могут быть выражены напрямую, если вообще могут быть выражены. С другой стороны, это полезно, потому что если тип является допустимым конструктивным доказательством, то термин этого типа является средством конструирования того, что вы доказали существование .

Главная особенность конструктивистского духа состоит в том, что двойное отрицание не эквивалентно неотрицанию. Фактически, отрицание редко является примитивом в системе типов, поэтому вместо этого мы можем представить его как подразумевающую ложь, например, not Pстановится P -> Falsity. Таким образом, двойное отрицание было бы функцией с типом (P -> Falsity) -> Falsity, которая явно не эквивалентна чему-то просто типу P.

Однако в этом есть интересный поворот! В языке с параметрическим полиморфизмом переменные типа охватывают все возможные типы, включая необитаемые, так что полностью полиморфный тип, такой как ∀a. aв некотором смысле, почти ложен. Так что, если мы напишем двойное почти отрицание с помощью полиморфизма? Мы получаем тип , который выглядит следующим образом : ∀a. (P -> a) -> a. Это что-то вроде типа P? Действительно , просто примените его к функции идентичности.

Но в чем смысл? Зачем писать такой шрифт? Означает ли это что- нибудь с точки зрения программирования? Что ж, вы можете думать об этом как о функции, которая где-то уже имеет что-то типа Pи требует, чтобы вы дали ей функцию, которая принимает Pв качестве аргумента, причем все это является полиморфным в конечном типе результата. В некотором смысле он представляет собой приостановленное вычисление , ожидающее выполнения остальных. В этом смысле эти приостановленные вычисления можно составлять вместе, передавать, вызывать и т. Д. Это должно показаться знакомым поклонникам некоторых языков, таких как Scheme или Ruby, потому что это означает, что двойное отрицание соответствует стилю передачи продолжения., и на самом деле тип, который я привел выше, является в точности продолжением монады в Haskell.

CA McCann
источник
Спасибо за исправление, я удалил «фальшь» как синоним непрекращения. +1 за двойное отрицание <=> CPS!
Tom Crockett
Я не совсем понимаю, как представить ¬p как P -> Falsity. Я понимаю, почему это работает (¬p ≡ p → ⊥), но не получил версию кода. P -> ⊥должны быть заселены именно тогда, когда Pнет, не так ли? Но разве эта функция не должна всегда быть обитаемой? Или возможно никогда, на самом деле, поскольку вы не можете вернуть экземпляр ? Я не совсем понимаю, насколько это обусловлено. Что тут за интуиция?
Antal Spector-Zabusky
1
@Antal SZ: Интуиция - это, конечно, интуиционистская логика! Но да, на самом деле написать такую ​​функцию сложно. В вашем профиле я вижу, что вы знакомы с Haskell, так что, может быть, вы думаете об алгебраических типах данных и сопоставлении с образцом? Учтите, что необитаемый тип не должен иметь конструкторов и, следовательно, не с чем сравнивать образец. Вам придется написать «функцию» без тела, что не разрешено в Haskell. На самом деле, насколько мне известно, в Haskell невозможно написать термин отрицательного типа без использования исключений времени выполнения или без завершения.
CA McCann,
1
@Antal SZ: С другой стороны, если эквивалентная логика согласована, все функции должны быть полными, например, все сопоставления с образцом должны быть исчерпывающими. Итак, чтобы написать функцию без шаблонов, тип параметра не должен иметь конструкторов, например быть необитаемым. Следовательно, такая функция будет законной - и, следовательно, ее собственный тип - обитаемым - именно и только тогда, когда ее аргумент необитаем. Следовательно, функция P -> Falsityэквивалентна Pложной.
CA McCann,
Ага, думаю, я понял. Версия, которую я развлекал, была чем-то вроде f x = x, которая была бы инстанциирована, если бы и только тогда P = ⊥, но она явно не была достаточно общей. Идея состоит в том, что для возврата типа без значения вам не нужно тело; но для того, чтобы функция была определяемой и полной, вам не нужны кейсы , и поэтому, если Pона необитаемая, все работает? Это немного шатко, но я думаю, что вижу это. Кажется, это довольно странно взаимодействует с моим определением Xorтипа… Надо подумать. Спасибо!
Antal Spector-Zabusky
15

Ваш график не совсем правильный; во многих случаях вы путаете типы с терминами.

function type              implication
function                   proof of implication
function argument          proof of hypothesis
function result            proof of conclusion
function application RULE  modus ponens
recursion                  n/a [1]
structural induction       fold (foldr for lists)
mathematical induction     fold for naturals (data N = Z | S N)
identity function          proof of A -> A, for all A
non-terminating function   n/a [2]
tuple                      normal proof of conjunction
sum                        disjunction
n/a [3]                    first-order universal quantification
parametric polymorphism    second-order universal quantification
currying                   (A,B) -> C -||- A -> (B -> C), for all A,B,C
primitive type             axiom
types of typeable terms    theory
function composition       syllogism
substitution               cut rule
value                      normal proof

[1] Логика функционального языка, полного по Тьюрингу, противоречива. Рекурсия не имеет соответствия в непротиворечивых теориях. В противоречивой логике / теории необоснованных доказательств вы могли бы назвать это правилом, которое вызывает несогласованность / несостоятельность.

[2] Опять же, это следствие полноты. Это было бы доказательством анти-теоремы, если бы логика была последовательной - а значит, ее не могло бы быть.

[3] Не существует в функциональных языках, так как они исключают логические особенности первого порядка: вся количественная оценка и параметризация выполняется по формулам. Если бы у вас были функции первого порядка, были бы и другие, чем *, * -> *и т.д .; вид элементов области дискурса. Например, в Father(X,Y) :- Parent(X,Y), Male(X), Xи Yохватывают область дискурса (назовите это Dom), и Male :: Dom -> *.

Фрэнк Атанассов
источник
[1] - да, я должен был быть более конкретным. Я имел в виду «структурную рекурсию», а не безусловную рекурсию, которая, как я полагаю, то же самое, что и «складывание». [3] - это действительно существует в языках с зависимой типизацией
Том Крокетт
[1] Дело в том, что если вызов функции рекурсии (modus ponens) не приводит к тому, что программа не завершается, параметры (гипотезы), данные вызову или среде, ДОЛЖНЫ быть разными для этих вызовов. Итак, рекурсия просто применяет одну и ту же теорему несколько раз. Если есть что-то особенное, это обычно увеличение / уменьшение числа (шаг индукции) и проверка с существующим случаем (базовый случай), что соответствует - Математической индукции в логике.
Earth Engine
Мне очень нравится эта диаграмма, но я бы не сказал «н / п», поскольку последовательная логика - не единственный вид логики, так же как завершение программы - не единственный вид программы. Непрерывная функция соответствовала бы «циклическому аргументу» и является прекрасной иллюстрацией изоморфизма Карри-Ховарда: «следование» циклическому аргументу помещает вас в бесконечный цикл.
Джои Адамс
13

Мне очень нравится этот вопрос. Я не очень много знаю, но кое-что у меня есть (чему помогает статья в Википедии , в которой есть несколько изящных таблиц и тому подобное):

  1. Я думаю, что типы суммы / типы объединения ( например data Either a b = Left a | Right b ) эквивалентны инклюзивной дизъюнкции. И хотя я не очень хорошо знаком с Карри-Ховардом, я думаю, что это демонстрирует это. Рассмотрим следующую функцию:

    andImpliesOr :: (a,b) -> Either a b
    andImpliesOr (a,_) = Left a
    

    Если я правильно понимаю, тип говорит, что ( a  ∧  b ) → ( a  ★  b ), а определение говорит, что это правда, где ★ либо включающее, либо исключающее, либо, в зависимости от того, что Eitherпредставляет. Вы Eitherпредставляете эксклюзивное или, ⊕; однако ( a  ∧  b ) ↛ ( a  ⊕  b ). Например, ⊤ ∧ ⊤ ≡ ⊤, но ⊤ ⊕ ⊥ ≡ ⊥ и ⊤ ↛ ⊥. Другими словами, если и a, и b верны, тогда гипотеза верна, но вывод неверен, и поэтому это предположение должно быть ложным. Однако ясно, что ( a  ∧  b ) → ( a  ∨ б ), поскольку если и a, и b истинны, то по крайней мере одно истинно. Таким образом, если размеченные союзы являются некоторой формой дизъюнкции, они должны быть инклюзивным разнообразием. Я думаю, что это является доказательством, но не стесняйтесь разубедить меня в этом мнении.

  2. Точно так же ваши определения тавтологии и абсурда как функции идентичности и функции без завершения, соответственно, немного ошибочны. Истинная формула представлена типом единицы измерения , который имеет только один элемент ( data ⊤ = ⊤часто пишется по буквам ()и / или Unitв языках функционального программирования). В этом есть смысл: поскольку этот тип гарантированно обитаем, и поскольку существует только один возможный житель, это должно быть правдой. Функция идентичности просто представляет собой особую тавтологию, согласно которой a  →  a .

    Ваш комментарий о непрерывных функциях, в зависимости от того, что именно вы имели в виду, более неуместен. Карри-Ховард работает в системе типов, но незавершение в ней не кодируется. Согласно Википедии , работа с незавершением является проблемой, так как добавление его приводит к противоречивой логике ( например , я могу определить с wrong :: a -> bпомощью wrong x = wrong xи, таким образом, «доказать», что a  →  b для любых a и b ). Если это то, что вы имели в виду под «абсурдом», то вы совершенно правы. Если вместо этого вы имели в виду ложное утверждение, то вместо этого вам нужен любой необитаемый тип, например, что-то определенноеdata ⊥- то есть тип данных без возможности его создания. Это гарантирует, что у него вообще нет значений, и поэтому он должен быть необитаемым, что эквивалентно false. Я думаю, что вы, вероятно, также могли бы использовать a -> b, так как если мы запретим неразрывные функции, то это тоже необитаемо, но я не уверен на 100%.

  3. Википедия говорит, что аксиомы кодируются двумя разными способами, в зависимости от того, как вы интерпретируете Карри-Ховарда: либо в комбинаторах, либо в переменных. Я думаю, что представление комбинатора означает, что предоставленные нам примитивные функции кодируют то, что мы можем сказать по умолчанию (аналогично тому, как modus ponens является аксиомой, потому что приложение функции является примитивным). И я думаю, что представление переменных на самом деле может означать то же самое - комбинаторы, в конце концов, - это просто глобальные переменные, которые являются конкретными функциями. Что касается примитивных типов: если я правильно об этом думаю, то я думаю, что примитивные типы - это сущности - примитивные объекты, относительно которых мы пытаемся что-то доказать.

  4. Согласно моему классу логики и семантики, тот факт, что ( a  ∧  b ) →  c  ≡  a  → ( b  →  c ) (а также, что b  → ( a  →  c )) называется законом эквивалентности экспорта, по крайней мере, в естественном выводе доказательства. В то время я не заметил, что это просто карри - я бы хотел, потому что это круто!

  5. Хотя теперь у нас есть способ представить инклюзивную дизъюнкцию, у нас нет способа представить исключительное разнообразие. Мы должны иметь возможность использовать определение исключительной дизъюнкции для ее представления: a  ⊕  b  ≡ ( a  ∨  b ) ∧ ¬ ( a  ∧  b ). Я не знаю, как писать отрицание, но я знаю, что ¬ p  ≡  p  → ⊥, и и импликация, и ложь - это легко. Таким образом, мы должны иметь возможность представить исключительную дизъюнкцию с помощью:

    data ⊥
    data Xor a b = Xor (Either a b) ((a,b) -> ⊥)
    

    Это определяется как пустой тип без значений, что соответствует ложности; XorЗатем определяется , чтобы содержать оба ( и ) или б ( или ) и функцию ( Подразумевается ) из (а, б) ( а ) к нижнему типу ( ложной ). Однако я понятия не имею, что это значит . ( Правка 1: Теперь да, см. Следующий абзац!) Поскольку нет значений типа (есть ли?), Я не могу понять, что это будет означать в программе. Кто-нибудь знает, как лучше подумать об этом или другом определении?Either(a,b) -> ⊥ ( Редактировать 1: Да, camccann .)

    Изменить 1: Благодаря ответу camccann (в частности, комментариям, которые он оставил, чтобы помочь мне), я думаю, что вижу, что здесь происходит. Чтобы создать значение типа Xor a b, вам нужно предоставить две вещи. Во-первых, свидетельство существования элемента любого aили bв качестве первого аргумента; то есть a Left aили a Right b. И во-вторых, доказательство того, что нет элементов обоих типов, aи b- другими словами, доказательство (a,b)необитаемости - в качестве второго аргумента. Так как вы только будете в состоянии написать функцию из , (a,b) -> ⊥если (a,b)необитаем, что это значит для того , чтобы быть дело? Это означало бы, что некоторая часть объекта типа(a,b)не мог быть построен; другими словами, что , по меньшей мере , один, и , возможно , оба, aи bнеобитаемые , как хорошо! В этом случае, если мы думаем о сопоставлении с образцом, вы не могли бы найти сопоставление с образцом для такого кортежа: предположим, что bон необитаемый, что бы мы написали, что могло бы соответствовать второй части этого кортежа? Таким образом, мы не можем сопоставить его с шаблоном, что может помочь вам понять, почему это делает его необитаемым. Теперь единственный способ иметь общую функцию, которая не принимает аргументов (как это и должно быть, поскольку (a,b)она необитаема), - это сделать результат также необитаемого типа - если мы думаем об этом с точки зрения сопоставления с образцом, это означает, что даже если у функции нет случаев, нет возможного тела могло быть и то, и другое, так что все в порядке.

Многое из этого я размышляю вслух / доказываю (надеюсь) на лету, но я надеюсь, что это полезно. Я очень рекомендую статью в Википедии ; Я не читал его подробно, но его таблицы - действительно хорошее резюме, и оно очень тщательное.

Антал Спектор-Забуски
источник
1
+1 за указание на то, что Either включает или. Обратите внимание, что (Либо aa) является теоремой (для всех a).
Apocalisp
Вопрос re. 2 (b): в чем разница между типом функции, единственный обитатель которой не завершается, и необитаемым типом функции? Например, если я объявил тип B без конструкторов, а затем определил функцию A-> B следующим образом: fun (a: A): B: = f (a) это будет проверять тип на многих языках, даже если это невозможно когда-либо вернуть B. Таким образом, функция в каком-то смысле "обитаема", но ее "обитатель" абсурден ... так что на самом деле она вообще не заселена. Надеюсь, в этом есть какой-то смысл :)
Том Крокетт
3
Низ не является доказательством. «Абсурдно и невозможно предполагать, что непознаваемое и неопределенное должно содержать и определять». - Аристотель
Апокалисп
2
@Tom: Просто чтобы донести мысль о незавершении: если логика согласована, все программы завершаются . Непрерывность возникает только в системах типов, представляющих противоречивую логику, или, что то же самое, в системах типов для полных по Тьюрингу языков.
CA McCann,
1
Апокалисп: Either a a не должно быть теоремой: Either ⊥ ⊥все еще необитаем. Том: Как сказал Камканн, последовательность подразумевает прекращение. Таким образом, согласованная система типов не позволит вам выразить f :: a -> b, и поэтому тип будет необитаемым; несовместимая система типов будет иметь обитателя для типа, но не завершится. camccann: Существуют ли несовместимые системы типов, которые не являются полными по Тьюрингу и занимают промежуточную точку в иерархии? Или этот последний шаг (добавление общей рекурсии или что-то еще) в точности эквивалентен несогласованности?
Antal Spector-Zabusky
12

Вот несколько непонятный вопрос, который, к моему удивлению, не упоминался ранее: «классическое» функциональное реактивное программирование соответствует временной логике.

Конечно, если вы не философ, математик или одержимый функциональным программистом, это, вероятно, поднимет еще несколько вопросов.

Итак, для начала: что такое функциональное реактивное программирование? Это декларативный способ работы со значениями, изменяющимися во времени . Это полезно для написания таких вещей, как пользовательские интерфейсы, потому что вводимые пользователем значения являются значениями, которые меняются со временем. «Классический» FRP имеет два основных типа данных: события и поведение.

События представляют собой значения, которые существуют только в дискретное время. Нажатие клавиш - отличный пример: вы можете думать о вводе с клавиатуры как о символе в данный момент. Каждое нажатие клавиши - это просто пара с символом клавиши и временем ее нажатия.

Поведение - это ценности, которые существуют постоянно, но могут постоянно меняться. Положение мыши - отличный пример: это просто поведение координат x, y. В конце концов, у мыши всегда есть позиция, и концептуально это положение постоянно изменяется при перемещении мыши. В конце концов, перемещение мыши - это единичное длительное действие, а не набор отдельных шагов.

А что такое темпоральная логика? Соответственно, это набор логических правил для работы с предложениями, количественно оцениваемыми с течением времени. По сути, он расширяет нормальную логику первого порядка двумя кванторами: □ и ◇. Первое означает «всегда»: читаем □ φ как «φ всегда выполняется». Второй - «в конце концов»: φ означает, что «в конечном итоге сохранится». Это особый вид модальной логики . Следующие два закона связывают кванторы:

□φ ⇔ ¬◇¬φ
◇φ ⇔ ¬□¬φ

Итак, □ и двойственны друг другу так же, как и ∃.

Эти два квантификатора соответствуют двум типам в FRP. В частности, □ соответствует поведению, а ◇ - событиям. Если мы подумаем о том, как эти типы заселены, это должно иметь смысл: поведение заселяется каждый возможный момент, а событие происходит только один раз.

Тихон Джелвис
источник
8

Связанный с отношениями между продолжениями и двойным отрицанием, тип call / cc - это закон Пирса http://en.wikipedia.org/wiki/Call-with-current-continuation

CH обычно утверждается как соответствие между интуиционистской логикой и программами. Однако, если мы добавим оператор call-with-current-continue (callCC) (тип которого соответствует закону Пирса), мы получим соответствие между классической логикой и программами с callCC.

Джеймс Айри
источник
4

Хотя это не простой изоморфизм, обсуждение конструктивной LEM является очень интересным результатом. В частности, в заключительном разделе Олег Киселев обсуждает, как использование монад для получения исключения двойного отрицания в конструктивной логике аналогично различению вычислительно разрешимых суждений (для которых LEM действительна в конструктивном контексте) от всех суждений. Представление о том, что монады захватывают вычислительные эффекты, является старым, но этот пример изоморфизма Карри-Ховарда помогает представить его в перспективе и помогает понять, что на самом деле «означает» двойное отрицание.

крапивник романо
источник
4

Первоклассная поддержка продолжений позволяет выразить $ P \ lor \ neg P $. Уловка основана на том факте, что отказ от вызова продолжения и выхода с каким-либо выражением эквивалентен вызову продолжения с тем же выражением.

Более подробную информацию см. На странице http://www.cs.cmu.edu/~rwh/courses/logic/www-old/handouts/callcc.pdf.

Даниил
источник
Спасибо за понимание!
paulotorrens
4
2-continuation           | Sheffer stoke
n-continuation language  | Existential graph
Recursion                | Mathematical Induction

Одна вещь, которая важна, но еще не исследована, - это взаимосвязь 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-продолжение, но я не видел, чтобы какие-либо существующие языки были в этой форме. Думаю, изобрести его может быть интересно.

Земляной двигатель
источник