Теория зависимого типа и функции произвольного типа
Мой первый ответ на этот вопрос был высоким по понятиям и низким по деталям и отразился на подвопросе «что происходит?»; этот ответ будет таким же, но сфокусирован на вопросе: «можем ли мы получить функции произвольного типа?».
Одним из расширений алгебраических операций суммы и произведения являются так называемые «большие операторы», которые представляют сумму и произведение последовательности (или, в более общем смысле, сумму и произведение функции над областью), обычно записываемые Σ
и Π
соответственно. Смотрите сигма нотации .
Итак, сумма
a₀ + a₁X + a₂X² + ...
может быть написано
Σ[i ∈ ℕ]aᵢXⁱ
где a
некоторая последовательность действительных чисел, например. Продукт будет представлен аналогично Π
вместо Σ
.
Когда вы смотрите издалека, этот вид выражения во многом похож на «произвольную» функцию X
; Конечно, мы ограничены выразимыми рядами и связанными с ними аналитическими функциями. Является ли это кандидатом на представление в теории типов? Определенно!
Класс теорий типов, которые непосредственно представляют эти выражения, является классом теорий «зависимых» типов: теорий с зависимыми типами. Естественно, у нас есть термины, зависящие от терминов, и в таких языках, как Haskell, с функциями типов и определением типов, терминами и типами в зависимости от типов. В зависимой настройке у нас также есть типы в зависимости от условий. Haskell не является языком с зависимой типизацией, хотя многие свойства зависимых типов могут быть смоделированы с помощью некоторой пытки языка .
Карри-Ховард и зависимые типы
«Изоморфизм Карри-Говарда» начал свою жизнь как наблюдение, что термины и правила оценки типов лямбда-исчисления с простыми типами в точности соответствуют естественному дедукции (сформулированной Генценом), примененной к интуиционистской логике высказываний, с типами, заменяющими суждения и термины, занимающие место доказательств, несмотря на то, что оба были изобретены / открыты независимо. С тех пор это стало огромным источником вдохновения для теоретиков типов. Одна из наиболее очевидных вещей, которую следует рассмотреть, - может ли и как это соответствие для логики высказываний быть распространено на логику предикатов или логики более высокого порядка. Теории зависимого типа изначально возникли на этом пути исследования.
Для ознакомления с изоморфизмом Карри-Ховарда для простейшего типа лямбда-исчисления см. Здесь . Например, если мы хотим доказать, A ∧ B
мы должны доказать A
и доказать B
; комбинированное доказательство - это просто пара доказательств: по одному на каждое соединение.
При естественном удержании:
Γ ⊢ A Γ ⊢ B
Γ ⊢ A ∧ B
и в простом наборе лямбда-исчисление:
Γ ⊢ a : A Γ ⊢ b : B
Γ ⊢ (a, b) : A × B
Аналогичные соответствия существуют для ∨
типов и сумм, →
и типов функций, и различных правил исключения.
Недоказуемое (интуитивно ложное) суждение соответствует необитаемому типу.
Имея в виду аналогию типов как логических суждений, мы можем начать думать о том, как моделировать предикаты в мире типов. Есть много способов, которыми это было формализовано (см. Это введение в Интуиционистскую Теорию Типа Мартина-Лёфа для широко используемого стандарта), но абстрактный подход обычно отмечает, что предикат подобен предложению со свободными переменными термина, или, альтернативно, функция, принимающая условия к предложениям. Если мы позволим выражениям типа содержать термины, тогда обработка в стиле лямбда-исчисления сразу же представится как возможность!
Учитывая только конструктивные доказательства, что представляет собой доказательство ∀x ∈ X.P(x)
? Мы можем думать об этом как о функции доказательства, переводя члены ( x
) в доказательства их соответствующих предложений ( P(x)
). Таким образом, члены (доказательства) типа (предложения) ∀x : X.P(x)
являются «зависимыми функциями», которые для каждого x
в X
дают термин типа P(x)
.
Как насчет ∃x ∈ X.P(x)
? Нам нужен любой член X
, x
вместе с доказательством P(x)
. Таким образом, члены (доказательства) типа (предложения) ∃x : X.P(x)
являются «зависимыми парами»: выделенный термин x
в X
сочетании с термином типа P(x)
.
Запись: я буду использовать
∀x ∈ X...
для фактических утверждений о членах класса X
, и
∀x : X...
для выражений типа, соответствующих универсальной квантификации по типу X
. Аналогично для ∃
.
Комбинаторные соображения: продукты и суммы
Наряду с соответствием типов по Карри-Говарду с предложениями мы имеем комбинаторное соответствие алгебраических типов с числами и функциями, что является основным вопросом этого вопроса. К счастью, это можно распространить на зависимые типы, описанные выше!
Я буду использовать обозначение модуля
|A|
представить «размер» типа A
, сделать явным соответствие, обозначенное в вопросе, между типами и числами. Обратите внимание, что это понятие вне теории; Я не утверждаю, что в языке должен быть такой оператор.
Давайте посчитаем возможные (полностью редуцированные, канонические) члены типа
∀x : X.P(x)
который является типом зависимых функций, принимающих термины x
типа X
к терминам типа P(x)
. Каждая такая функция должна иметь вывод для каждого члена X
, и этот вывод должен быть определенного типа. Для каждого x
дюйма X
, то это дает |P(x)|
«выбор» вывод.
Изюминка
|∀x : X.P(x)| = Π[x : X]|P(x)|
что, конечно, не имеет большого смысла, если X
есть IO ()
, но применимо к алгебраическим типам.
Точно так же термин типа
∃x : X.P(x)
тип пар (x, p)
с p : P(x)
, так что для любого x
в X
можно построить соответствующую пару с любым членом P(x)
, давая |P(x)|
«выбор».
Следовательно,
|∃x : X.P(x)| = Σ[x : X]|P(x)|
с такими же предостережениями.
Это оправдывает общее обозначение зависимых типов в теориях, использующих символы, Π
и Σ
, действительно, многие теории стирают различие между «для всех» и «продуктом» и между «есть» и «суммой» из-за вышеупомянутых соответствий.
Мы приближаемся!
Векторы: представление зависимых кортежей
Можем ли мы теперь кодировать числовые выражения, такие как
Σ[n ∈ ℕ]Xⁿ
как выражения типа?
Не совсем. Хотя мы можем неофициально рассмотреть значение выражений, таких как Xⁿ
в Haskell, где X
это тип и n
натуральное число, это злоупотребление нотацией; это выражение типа, содержащее число: явно не является допустимым выражением.
С другой стороны, с зависимыми типами на картинке, типы, содержащие числа, это как раз и есть точка; на самом деле, зависимые кортежи или «векторы» являются очень часто цитируемым примером того, как зависимые типы могут обеспечить прагматическую безопасность на уровне типов для таких операций, как доступ к списку . Вектор - это просто список вместе с информацией на уровне типов относительно его длины: именно то, что нам нужно для подобных выражений типа Xⁿ
.
Для продолжительности этого ответа, пусть
Vec X n
быть типом n
векторов X
длины значений -type.
Технически n
здесь, а не фактическое натуральное число, представление в системе натурального числа. Мы можем представлять натуральные числа ( Nat
) в стиле Пеано как ноль ( 0
) или как преемник ( S
) другого натурального числа, и n ∈ ℕ
я пишу ˻n˼
для обозначения термина, в Nat
котором он представлен n
. Например, ˻3˼
есть S (S (S 0))
.
Тогда у нас есть
|Vec X ˻n˼| = |X|ⁿ
для любого n ∈ ℕ
.
Типы Nat: продвижение ℕ терминов в типы
Теперь мы можем кодировать выражения как
Σ[n ∈ ℕ]Xⁿ
как типы. Это конкретное выражение приведет к типу, который, конечно, изоморфен типу списков X
, как указано в вопросе. (Не только это, но и с точки зрения теории категорий, функция типа - которая является функтором - переход X
к указанному выше типу естественным образом изоморфна функтору List.)
Последний фрагмент головоломки для «произвольных» функций - это как
f : ℕ → ℕ
выражения как
Σ[n ∈ ℕ]f(n)Xⁿ
так что мы можем применить произвольные коэффициенты к степенному ряду.
Мы уже понимаем соответствие алгебраических типов числам, что позволяет нам сопоставлять типы с числами и функции типов с числовыми функциями. Мы также можем пойти другим путем! - если взять натуральное число, то, очевидно, существует определимый алгебраический тип с таким количеством членов-членов, независимо от того, есть у нас зависимые типы или нет. Мы можем легко доказать это вне теории типов по индукции. Нам нужен способ отображения натуральных чисел на типы внутри системы.
Приятное осознание состоит в том, что, когда у нас есть зависимые типы, доказательство по индукции и построение по рекурсии становятся очень похожими - на самом деле, во многих теориях это одно и то же. Поскольку мы можем по индукции доказать, что существуют типы, которые удовлетворяют нашим потребностям, разве мы не можем их построить?
Существует несколько способов представления типов на уровне терминов. Я буду использовать здесь воображаемую нотацию по Хаскеллу *
для вселенной типов, которая обычно считается типом в зависимом окружении. 1
Аналогичным образом, существует также как минимум столько же способов обозначения « ℕ
исключения», сколько существует теорий зависимых типов. Я буду использовать Haskellish для сопоставления с образцом.
Нам необходимо отображение, α
от Nat
к *
, со свойством
∀n ∈ ℕ.|α ˻n˼| = n.
Достаточно следующего псевдодетерминации.
data Zero -- empty type
data Successor a = Z | Suc a -- Successor ≅ Maybe
α : Nat -> *
α 0 = Zero
α (S n) = Successor (α n)
Итак, мы видим, что действие α
отражает поведение преемника S
, делая его своего рода гомоморфизмом. Successor
является функцией типа, которая «добавляет единицу» к числу членов типа; то есть |Successor a| = 1 + |a|
для любого a
с определенным размером.
Например α ˻4˼
(что есть α (S (S (S (S 0))))
), это
Successor (Successor (Successor (Successor Zero)))
и условия этого типа
Z
Suc Z
Suc (Suc Z)
Suc (Suc (Suc Z))
давая нам точно четыре элемента: |α ˻4˼| = 4
.
Аналогично, для любого n ∈ ℕ
, у нас есть
|α ˻n˼| = n
как требуется.
- Многие теории требуют, чтобы члены
*
были просто представителями типов, а операция предоставляется как явное отображение терминов типа *
на связанные с ними типы. Другие теории допускают, чтобы сами буквальные типы были сущностями уровня термина.
«Произвольные» функции?
Теперь у нас есть аппарат для выражения общего общего степенного ряда в виде типа!
Сериал
Σ[n ∈ ℕ]f(n)Xⁿ
становится типом
∃n : Nat.α (˻f˼ n) × (Vec X n)
где ˻f˼ : Nat → Nat
некоторое подходящее представление на языке функции f
. Мы можем видеть это следующим образом.
|∃n : Nat.α (˻f˼ n) × (Vec X n)|
= Σ[n : Nat]|α (˻f˼ n) × (Vec X n)| (property of ∃ types)
= Σ[n ∈ ℕ]|α (˻f˼ ˻n˼) × (Vec X ˻n˼)| (switching Nat for ℕ)
= Σ[n ∈ ℕ]|α ˻f(n)˼ × (Vec X ˻n˼)| (applying ˻f˼ to ˻n˼)
= Σ[n ∈ ℕ]|α ˻f(n)˼||Vec X ˻n˼| (splitting product)
= Σ[n ∈ ℕ]f(n)|X|ⁿ (properties of α and Vec)
Насколько это «произвольно»? Этот метод ограничен не только целыми коэффициентами, но и натуральными числами. Помимо этого, f
может быть что угодно, учитывая язык Тьюринга, полный с зависимыми типами, мы можем представить любую аналитическую функцию с натуральными числовыми коэффициентами.
Я не исследовал взаимодействие этого, например, с случаем, представленным в вопросе о List X ≅ 1/(1 - X)
том, какой возможный смысл могут иметь такие отрицательные и нецелые «типы» в этом контексте.
Надеюсь, этот ответ каким-то образом исследует, как далеко мы можем зайти с функциями произвольного типа.