Изоморфизм Карри-Говарда

Я искал в интернете, и я не могу найти никаких объяснений Ци, которые не быстро вырождаются в лекцию по теории логики, которая резко над моей головой. (Эти люди говорят, что "интуитивистское исчисление пропозиций" - это фраза, которая на самом деле значит что-то для нормальных людей!)

грубо говоря, Ци говорит, что типы являются теоремами, а программы-доказательствами этих теорем. Но какого черта это вообще mean??

до сих пор я понял это:

  • считают id :: x -> x. Его тип говорит: "учитывая, что X истинно, мы можем заключить, что X истинно". Мне кажется, это разумная теорема.

  • Теперь рассмотрим foo :: x -> y. Как скажет вам любой программист Haskell, это невозможно. Вы не можете написать эту функцию. (Ну, во всяком случае без обмана.) Прочитайте как теорему, она говорит: "учитывая, что любой X истинен, мы можем заключить, что любой Y правдивый." Это, очевидно, бред. И, конечно же, вы не можете написать эту функцию.

  • в более общем плане аргументы функции можно рассматривать как "это, которое предполагается истинным", а тип результата можно рассматривать как"вещь, которая истинна, если все остальные вещи". Если есть аргумент функции, скажите x -> y, мы можем принять это как предположение, что X истинно означает, что Y должно быть истинным.

  • например, (.) :: (y -> z) -> (x -> y) -> x -> z can "если предположить, что Y подразумевает Z, что X подразумевает Y и что X истинно, мы можем заключить, что Z истинно". Что кажется мне логически разумным.

теперь, что, черт возьми Int -> Int в смысле?? О_о

единственный разумный ответ, который я могу придумать, это: если у вас есть функция X - > Y - > Z, то подпись типа говорит: "предполагая, что можно построить значение типа X, а другое типа Y, то можно построить значение типа Зет." И тело функции точно описывает, как вы это сделаете.

это, кажется, имеет смысл, но это не очень интересные. Ясно, что за этим кроется нечто большее...

3 ответов


изоморфизм Карри-Говарда просто утверждает, что типы соответствуют пропозициям, а значения соответствуют доказательствам.

Int -> Int на самом деле не означает много интересного как логическое предложение. При интерпретации чего-либо как логического предложения вас интересует только то, является ли тип Обитаемый (имеет никакого значения) или нет. Итак,Int -> Int значит "дали Int, Я могу дать вам - это просто определенный вид логики, которому соответствуют общие функциональные языки. Важно отметить, что это конструктивное: в принципе, доказательство a -> b дает алгоритм вычислить b С a, что неверно в обычной классической логике (из-за закон исключенного третьего, который скажет вам, что что-то либо истинно, либо ложно, но не почему).

даже если функции как Int -> Int не много значит как предложения, мы можем делать утверждения о них с другими предложениями. Например, мы можем объявить тип равенства двух типов (используя GADT):

data Equal a b where
    Refl :: Equal a a

если у нас есть значение типа Equal a b, потом a тот же тип b: Equal a b соответствующее предложение a = b. Проблема в том, что мы можем говорить только о равенстве типы этот путь. Но если бы мы ... зависимые типы, мы могли бы легко обобщить это определение для работы с любой значением, и так Equal a b соответствовало бы предположению, что значения a и b идентичны. Так, например, мы могли бы написать:--25-->

type IsBijection (f :: a -> b) (g :: b -> a) =
    forall x. Equal (f (g x)) (g (f x))

здесь f и g обычные функции, так f может легко иметь тип Int -> Int. Опять же, Хаскелл не может этого сделать; вам нужно зависимые типы делают такие вещи.

типичные функциональные языки не очень хорошо подходят для написания доказательств не только потому, что им не хватает зависимых типов, но и из-за⊥, который, имея тип a для всех a, действует как доказательство любого предложения. Но!--83-->в общей сумме языки, как Coq и Agda использовать переписку в качестве системы доказательств, а также зависимо-типизированный программирования языки.


возможно, лучший способ понять, что это означает начать (или попробовать) используя типы как предложения и программы в качестве доказательств. Лучше изучать язык с зависимыми типами, такими как Agda (это написано в Haskell и похоже на Haskell). Существуют различные статьи и курсы на этом языке. узнать вас Agda является неполным, но стараюсь все упрощать, как LYAHFGG книга.

вот пример простого доказательства:

{-# OPTIONS --without-K #-} -- we are consistent

module Equality where

-- Peano arithmetic.
-- 
--   ℕ-formation:     ℕ is set.
-- 
--   ℕ-introduction:  o ∈ ℕ,
--                    a ∈ ℕ | (1 + a) ∈ ℕ.
-- 
data ℕ : Set where
  o : ℕ
  1+ : ℕ → ℕ

-- Axiom for _+_.
-- 
--   Form of ℕ-elimination.
-- 
infixl 6 _+_
_+_ : ℕ → ℕ → ℕ
o + m = m
1+ n + m = 1+ (n + m)

-- The identity type for ℕ.
-- 
infix 4 _≡_
data _≡_ (m : ℕ) : ℕ → Set where
  refl : m ≡ m

-- Usefull property.
-- 
cong : {m n : ℕ} → m ≡ n → 1+ m ≡ 1+ n
cong refl = refl

-- Proof _of_ mathematical induction:
-- 
--   P 0, ∀ x. P x → P (1 + x) | ∀ x. P x.
-- 
ind : (P : ℕ → Set) → P o → (∀ n → P n → P (1+ n)) → ∀ n → P n
ind P P₀ _ o = P₀
ind P P₀ next (1+ n) = next n (ind P P₀ next n)

-- Associativity of addition using mathematical induction.
-- 
+-associative : (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-associative m n p = ind P P₀ is m
  where
    P : ℕ → Set
    P i = (i + n) + p ≡ i + (n + p)
    P₀ : P o
    P₀ = refl
    is : ∀ i → P i → P (1+ i)
    is i Pi = cong Pi

-- Associativity of addition using (dependent) pattern matching.
-- 
+-associative′ : (m n p : ℕ) → (m + n) + p ≡ m + (n + p)
+-associative′ o _ _ = refl
+-associative′ (1+ m) n p = cong (+-associative′ m n p)

там вы можете увидеть (m + n) + p ≡ m + (n + p) предложение как тип и его доказательство как функция. Существуют более продвинутые методы для таких доказательств (например, предзаказ рассуждения, комбинаторы в Agda похожи на тактику в Coq).

что еще можно доказать:

  • head ∘ init ≡ head для векторов, здесь.

  • ваш компилятор создает программу какое выполнение дает то же значение, что и значение, полученное в интерпретации той же (хост -) программы, здесь, для Coq. книги также является хорошим чтением по теме моделирования языка и проверки программ.

  • все остальное, что может быть доказано в конструктивной математике, так как теория типов Мартина-Лефа в своей выразительной силе эквивалентна ZFC. Фактически, изоморфизм Карри-Говарда может быть расширен до физика и топология и алгебраической топологии.


единственный разумный ответ, который я могу придумать, таков: Если у вас есть функция X -> Y -> Z, то подпись типа говорит: "предполагая, что можно построить значение типа X, а другое типа Y, то можно построить значение типа Z". И тело функции точно описывает, как вы это сделаете. В этом есть смысл, но это не очень интересно. Ясно, что за этим кроется нечто большее...

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

прежде всего, ваше обсуждение Ци оформлено исключительно в терминах типов импликации / функции (->). Вы не говорите об этом, но вы, вероятно, видели, как конъюнкция и дизъюнкция соответствуют типам продукта и суммы соответственно. Но как насчет других логических операторов, таких как отрицание, универсальная квантификация и экзистенциальная квантификация? Как мы перевести логические доказательства, связанные с ними, в программы? Получается, что примерно так:

  • отрицание соответствует первоклассные продолжения. Не проси меня объяснить это.
  • универсальная квантификация над пропозициональными (не индивидуальными) переменными соответствует параметрический полиморфизм. Так, например, полиморфная функция id действительно имеет тип forall a. a -> a
  • экзистенциальное квантификация над пропозициональными переменными соответствует нескольким вещам, которые имеют отношение к скрытию данных или реализации:абстрактные типы данных, системы и динамическая диспетчеризация. Экзистенциальные типы GHC связаны с этим.
  • универсальная и экзистенциальная квантификация по отдельным переменным приводит к зависимые системы типов.

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

теперь, что, черт возьми, означает Int - > Int?? О_о

это тип, или же предложение. В f :: Int -> Int, (+1) называет " программу "(в определенном смысле, который допускает как функции, так и константы как "программы", или альтернативно доказательство. Семантика языка должна либо обеспечивать f как примитивное правило вывода, или продемонстрировать, как f является доказательством, которое может быть построено из таких правил и предпосылок.

эти правила часто указываются с точки зрения эквациональной аксиом, которые определяют члены базового типа и правила, которые позволяют доказать, что других программ населяют этот тип. Например, переключение с Int to Nat (натуральные числа от 0 forward), мы могли бы иметь следующие правила:

  • аксиомы: 0 :: Nat (0 примитивное доказательство Nat)
  • правила: x :: Nat ==> Succ x :: Nat
  • правила: x :: Nat, y :: Nat ==> x + y :: Nat
  • правила: x + Zero :: Nat ==> x :: Nat
  • правила: Succ x + y ==> Succ (x + y)

эти правила достаточно, чтобы доказать многие теоремы о сложении натуральных чисел. Эти доказательства также будут программами.