Подтвердить что ты не робот

Что такое кванторы типа?

Многие статически типизированные языки имеют параметрический полиморфизм. Например, в С# можно определить:

T Foo<T>(T x){ return x; }

На сайте вызова вы можете:

int y = Foo<int>(3);

Эти типы также иногда записываются следующим образом:

Foo :: forall T. T -> T

Я слышал, как люди говорят, что "forall похоже на лямбда-абстракцию на уровне уровня". Таким образом, Foo - это функция, которая принимает тип (например, int) и выдает значение (например, функцию типа int → int). Многие языки выводят параметр типа, поэтому вы можете написать Foo(3) вместо Foo<int>(3).

Предположим, что у нас есть объект f типа forall T. T -> T. Что мы можем сделать с этим объектом, сначала передаем ему тип Q, написав f<Q>. Затем мы возвращаем значение с типом Q -> Q. Однако определенные f недействительны. Например, это f:

f<int> = (x => x+1)
f<T> = (x => x)

Итак, если мы "вызываем" f<int>, то возвращаем значение с типом int -> int, и вообще, если мы "вызываем" f<Q>, мы возвращаем значение с типом Q -> Q, так что хорошее, Однако обычно понимается, что этот f не является допустимым типом типа forall T. T -> T, потому что он делает что-то другое в зависимости от того, какой тип вы его передаете. Идея forall заключается в том, что это явно запрещено. Кроме того, если forall является лямбдой для уровня типа, то что существует? (т.е. экзистенциальное количественное определение). По этим причинам кажется, что forall и exist на самом деле не "лямбда на уровне типа". Но что они? Я понимаю, что этот вопрос довольно расплывчатый, но может ли кто-нибудь прояснить это для меня?


  

Возможное объяснение следующее:

         

Если мы посмотрим на логику, кванторы и лямбда - две разные вещи. Пример количественного выражения:

forall n in Integers: P(n)
         

Таким образом, для forall есть две части: набор для количественной оценки (например, целые числа) и предикат (например, P). Forall можно рассматривать как функцию более высокого порядка:

forall n in Integers: P(n) == forall(Integers,P)
         

С типом:

forall :: Set<T> -> (T -> bool) -> bool
         

Exists имеет тот же тип. Forall - бесконечная конъюнкция, где S [n] - n-й элемент множества S:

forall(S,P) = P(S[0]) ∧ P(S[1]) ∧ P(S[2]) ...
         

Существует как бесконечная дизъюнкция:

exists(S,P) = P(S[0]) ∨ P(S[1]) ∨ P(S[2]) ...
         

Если мы проведем аналогию с типами, можно сказать, что аналогом типа ∧ является вычисление типа пересечения ∩ и аналогом типа ∨, вычисляющим тип объединения ∪. Затем мы могли бы определить forall и существовать по типам следующим образом:

forall(S,P) = P(S[0]) ∩ P(S[1]) ∩ P(S[2]) ...
exists(S,P) = P(S[0]) ∪ P(S[1]) ∪ P(S[2]) ...
         

Таким образом, forall является бесконечным пересечением, и существует бесконечный союз. Их типы:

forall, exists :: Set<T> -> (T -> Type) -> Type
         

Например, тип функции полиморфного идентификатора. Здесь Types - множество всех типов, а -> - конструктор типов для функций, а => - абстракция лямбда:

forall(Types, t => (t -> t))
         

Теперь тип типа forall T:Type. T -> T является значением, а не функцией от типов к значениям. Это значение, тип которого является пересечением всех типов T → T, где T пробегает все типы. Когда мы используем такое значение, нам не нужно применять его к типу. Вместо этого мы используем суждение подтипа:

id :: forall T:Type. T -> T
id = (x => x)

id2 = id :: int -> int
         

Это означает, что id имеет тип int -> int. Это справедливо, так как int -> int также появляется в бесконечном пересечении.

         

Это хорошо работает, я думаю, и он ясно объясняет, что такое forall, и чем оно отличается от лямбда, но эта модель несовместима с тем, что я видел на таких языках, как ML, F #, С# и т.д. Например, в F # вы выполняете id<int>, чтобы получить функцию идентификации в int, что не имеет смысла в этой модели: id - это функция для значений, а не функция для типов, возвращающая функцию на значения.

  

Может ли кто-нибудь, кто знает теорию типов, объяснить, что именно существует и существует? И насколько это верно, что "forall лямбда на уровне уровня"?

4b9b3361

Ответ 1

Позвольте мне отдельно задать ваши вопросы.

  • Вызов для всех "лямбда на уровне уровня" является неточным по двум причинам. Во-первых, это тип лямбды, а не сама лямбда. Во-вторых, эта лямбда живет на уровне термина, хотя она абстрагируется по типам (лямбды на уровне типа существуют также, они обеспечивают то, что часто называют родовыми типами).

  • Универсальная квантификация не обязательно подразумевает "одинаковое поведение" для всех экземпляров. Это особое свойство, называемое "параметричность", которое может быть или не быть. Простой полиморфный лямбда-исчисление является параметрическим, потому что вы просто не можете выразить какое-либо непараметрическое поведение. Но если вы добавляете такие конструкции, как typecase (анализ типа int.k.a.) или проверенные приведения в качестве более слабой формы, тогда вы теряете параметричность. Параметричность подразумевает хорошие свойства, например. он позволяет реализовать язык без представления типов во время выполнения. И это вызывает очень сильные принципы рассуждений, см., Например, Вадлерская бумага "Теоремы бесплатно!". Но это компромисс, иногда вам нужна отправка по типам.

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

    pack (Int, (& lambda; x. x, & lambda; x. x)): & exist; T. (Int → T) & times; (T → Int)

    Это простой ADT, представление которого является Int и оно предоставляет только две операции (как вложенный кортеж), для преобразования ints в и из абстрактного типа T. Это, например, основа теорий типов для модулей.

  • Таким образом, универсальная квантификация обеспечивает абстракцию данных на стороне клиента, тогда как экзистенциальные типы dually обеспечивают абстракцию данных на стороне разработчиков.

  • В качестве дополнительного замечания в так называемом лямбда-кубе все и стрелы обобщаются на унифицированное понятие типа & Pi; (где T1 → T2 = & Pi; (x: T1).T2 и & allall, AT = & Pi; (A: & ast;), T) и аналогично существует, и tupling может быть обобщен на & Sigma; -типы (где T1 и times; T2 = & Sigma; (x: T1).T2 и & существуют; AT = & Sigma; А: & AST;) Т).. Здесь тип & ast; это "тип типов".

Ответ 2

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

Во-первых, нельзя сказать, что forall является лямбда на уровне уровня, потому что уже существует понятие лямбда на уровне типа, и оно отличается от forall. Он появляется в системе F_omega, расширении System F с вычислением уровня на уровне, что полезно для объяснения систем модулей ML, например (F-ing modules, Андреас Росберг, Клаудио Руссо и Дерек Дрейер, 2010).

В (синтаксис для) System F_omega вы можете написать, например:

type prod =
  lambda (a : *). lambda (b : *).
    forall (c : *). (a -> b -> c) -> c

Это определение "конструктор типов" prod, например prod a b - тип церковного кодирования типа продукта (a, b). Если на уровне типа есть расчет, то вам нужно его контролировать, если вы хотите обеспечить завершение проверки типа (иначе вы могли бы определить тип (lambda t. t t) (lambda t. t t). Это делается с помощью "системы типов на уровне типа", или вид системы. prod будет иметь вид * -> * -> *. Только типы в виде * могут быть заселены значениями, типы на более высоком уровне могут применяться только на уровне типа. lambda (c : k) . .... - это тип абстракции уровня, который не может быть типом значения, и может жить в любом виде формы k -> ..., тогда как forall (c : k) . .... классифицирует значения, которые являются полиморфными в некотором типе c : k и обязательно является наземным видом *.

Во-вторых, существует важное различие между forall Системы F и Pi-типами теории типа Мартина-Лёфа. В System F полиморфные значения делают то же самое для всех типов. В первом приближении можно сказать, что значение типа forall a . a -> a будет (неявно) принимать тип t в качестве входного и возвращать значение типа t -> t. Но это говорит о том, что в процессе могут быть некоторые вычисления, что не так. Морально, когда вы создаете значение типа forall a. a -> a в значение типа t -> t, значение не изменяется. Есть три (связанных) способа подумать об этом:

  • У количественного определения системы F есть стирание типа, вы можете забыть о типах, и вы все равно знаете, что такое динамическая семантика программы. Когда мы используем вывод типа ML, чтобы оставить абстракцию и инстанцирование полиморфизма, неявную в наших программах, мы действительно не позволяем движку вывода "заполнить отверстия в нашей программе", если вы думаете о "программе" в качестве динамического объекта, который будет запущен и вычислить.

  • A forall a . foo не является чем-то, что "создает экземпляр foo для каждого типа a, но один тип foo, который является" общим для неизвестного типа a ".

  • Вы можете объяснить универсальное квантификацию как бесконечное соединение, но есть условие однородности, что все конъюнкты имеют одну и ту же структуру и, в частности, что их доказательства одинаковы.

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

Это имеет очень важные последствия, если вы обеспокоены обоснованностью этих формальных теорий. Система F является нецелесообразной (количественный количественный тип количественно на всех типах, включенных в себя), и причина, по которой это все еще звучит, - это однородность универсальной количественной оценки. При введении непараметрических конструкций разумно с точки зрения программиста (и мы все еще можем рассуждать о параметричности в целом непараметрическом языке), он очень быстро разрушает логическую согласованность базовой статической системы рассуждений. Предикативная теория Мартина-Лёфа гораздо проще доказать правильность и правильность распространения.

Для высокоуровневого описания этого аспекта однородности/общности системы F см. статью Fruchart and Longo 97 Замечания Карнапа об импрессивных определениях и теореме обобщенности. Для более технического исследования отказа системы F в присутствии непараметрических конструкций см. Параметричность и варианты оператора Girard J Роберта Харпера и Джона Митчелла (1999). Наконец, для описания, с точки зрения дизайна языка, о том, как отказаться от глобальной параметричности для введения непараметрических конструкций, но все же иметь возможность локально обсуждать параметричность, см. Непараметрическая параметричность Джорджа Нейса, Дерека Дрейера и Андреаса Россберга, 2011.

Это обсуждение разницы между "вычислительной абстракцией" и "равномерным абстрактным" было возрождено большим объемом работы по представлению переменных связующих. Связывающая конструкция выглядит как абстракция (и может быть смоделирована с помощью лямбда-абстракции в стиле HOAS), но имеет однородную структуру, которая делает ее скорее похожим на скелет данных, чем семейством результатов. Это было много обсуждено, например, в сообществе LF, "репрезентативных стрелках" в Twelf, "положительных стрелках" в работе Licata & Harper и т.д.

Недавно было несколько человек, которые работали над соответствующим понятием "неуместности" (лямбда-абстракции, где результат "не зависит" от аргумента), но еще не совсем ясно, насколько тесно это связано с параметрическим полиморфизмом. Одним из примеров является работа Натана Мишры-Лингера с Тимом Шиардом (например, Erasure и полиморфизм в системах чистого типа).

Ответ 3

если forall является lambda..., то что существует

Почему, конечно, кортеж!

В теория типа Мартина-Лёфа у вас есть Π-типы, соответствующие функциям/универсальному квантификации и Σ-типам, соответствующим набору/экзистенциальному количественному определению.

Их типы очень похожи на то, что вы предложили (я использую здесь Agda):

Π : (A : Set) -> (A -> Set) -> Set
Σ : (A : Set) -> (A -> Set) -> Set

Действительно, П - бесконечное произведение, а Σ - бесконечная сумма. Обратите внимание, что они не являются "пересечением" и "объединением", хотя, как вы предложили, потому что вы не можете этого сделать без дополнительного определения того, где пересекаются типы. (какие значения одного типа соответствуют значениям другого типа)

Из этих двух конструкторов типов вы можете иметь все нормальные, полиморфные и зависимые функции, нормальные и зависимые кортежи, а также экзистенциальные и универсально-квантованные утверждения:

-- Normal function, corresponding to "Integer -> Integer" in Haskell
factorial : Π ℕ (λ _ → ℕ)

-- Polymorphic function corresponding to "forall a . a -> a"
id : Π Set (λ A -> Π A (λ _ → A))

-- A universally-quantified logical statement: all natural numbers n are equal to themselves
refl : Π ℕ (λ n → n ≡ n)


-- (Integer, Integer)
twoNats : Σ ℕ (λ _ → ℕ)

-- exists a. Show a => a
someShowable : Σ Set (λ A → Σ A (λ _ → Showable A))

-- There are prime numbers
aPrime : Σ ℕ IsPrime

Однако это вовсе не относится к параметричности, а параметрическая AFAIK и теория типа Мартина-Лёфа независимы.

Для параметричности люди обычно ссылаются на работу Филиппа Вадлера.