Зависимые типы от церковно-закодированного типа в PTS / CoC

11

Я экспериментирую с системами чистого типа в лямбда-кубе Барендрегта, особенно с наиболее мощным, исчислением конструкций. Эта система имеет сорта *и BOX. Для справки ниже я использую конкретный синтаксис Morteинструмента https://github.com/Gabriel439/Haskell-Morte-Library, который близок к классическому лямбда-исчислению.

Я вижу, что мы можем эмулировать индуктивные типы с помощью некоторого церковно-подобного кодирования (так называемый изоморфизм Бёма-Берардуччи для алгебраических типов данных). Для простого примера я использую тип Bool = ∀(t : *) -> t -> t -> tс конструкторами True = λ(t : *) -> λ(x : t) -> λ(y : t) -> xи False = λ(t : *) -> λ(x : t) -> λ(y : t) -> y.

Я вижу, что тип функций уровня членов Bool -> Tизоморфен парам типа Product T Tс классической Product = λ(A : *) -> λ(B : *) -> ∀(t : *) -> (A -> B -> t) -> tпо модулю параметричности посредством функции, if : Bool -> λ(t : *) -> t -> t -> tкоторая фактически тождественна.

Все вопросы ниже будут о представлениях зависимых типов Bool -> *.

  1. Я могу разделить D : Bool -> *на пару D Trueи D False. Есть ли канонический способ создать Dзаново? Я хочу воспроизвести изоморфизм Bool -> T = Product T Tс помощью аналога функции ifна уровне типа, но я не могу написать эту функцию так же просто, как оригинал, ifпотому что мы не можем передавать виды в аргументах, таких как типы.

  2. Я использую своего рода индуктивный тип с двумя конструкторами для решения вопроса (1). Описание высокого уровня (стиль Agda) - это следующий тип (используется вместо уровня типа if)

    data BoolDep (T : *) (F : *) : Bool -> * where
      DepTrue : T -> BoolDep T F True
      DepFalse : F -> BoolDep T F False
    

    со следующей кодировкой в ​​PTS / CoC:

    λ(T : *) -> λ(F : *) -> λ(bool : Bool ) ->
    ∀(P : Bool -> *) ->
    ∀(DepTrue : T -> P True ) ->
    ∀(DepFalse : F -> P False ) ->
    P bool
    

    Правильна ли моя кодировка выше?

  3. Я могу записать конструкторы для BoolDepэтого кода для DepTrue : ∀(T : *) -> ∀(F : *) -> T -> BoolDep T F True:

    λ(T : *) ->  λ(F : *) ->  λ(arg : T ) ->
    λ(P : Bool -> *) ->
    λ(DepTrue : T -> P True ) ->
    λ(DepFalse : F -> P False ) ->
    DepTrue arg
    

но я не могу записать обратную функцию (или любую функцию в обратном направлении). Является ли это возможным? Или я должен использовать другое представление для BoolDepсоздания изоморфизма BoolDep T F True = T?

ZeitRaffer
источник
Product T TBoolTBoolT((t:)(ttt))TProductTT(t:)((TTt)t)
@ Джорджио Мосса см. Cstheory.stackexchange.com/questions/30923/… - если у вас есть параметричность (не во всех моделях, а в исходной (синтаксической)), то у вас есть изоморфизм.
ZeitRaffer

Ответы:

9

Вы не можете сделать это, используя традиционную церковную кодировку для Bool:

#Bool = ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool

... потому что вы не можете написать (полезную) функцию типа:

#Bool → *

Причина , почему, как вы отметили, что вы не можете передать в *качестве первого аргумента #Bool, который в свою очередь означает , что Trueи Falseаргументы не могут быть типы.

Есть как минимум три способа решить эту проблему:

  1. Используйте исчисление индуктивных конструкций. Тогда вы можете обобщить тип #Bool:

    #Bool = ∀(n : Nat) → ∀(Bool : *ₙ) → ∀(True : Bool) → ∀(False : Bool) → Bool
    

    ... и затем вы создадите экземпляр nдля 1, что означает, что вы можете передать в *₀качестве второго аргумента, который будет проверять тип, потому что:

    *₀ : *₁
    

    ... так что вы можете использовать #Boolдля выбора между двумя типами.

  2. Добавьте еще один сорт:

    * : □ : △
    

    Тогда вы бы определили отдельный #Bool₂тип следующим образом:

    #Bool₂ = ∀(Bool : □) → ∀(True : Bool) → ∀(False : Bool) → Bool
    

    По сути, это частный случай исчисления индуктивных конструкций, но он производит менее многократно используемый код, поскольку теперь мы должны поддерживать два отдельных определения #Bool, по одному для каждого вида, который мы хотим поддерживать.

  3. Кодировать #Bool₂непосредственно в исчислении конструкций как:

    #Bool₂ = ∀(True : *) → ∀(False : *) → *
    

Если цель состоит в том, чтобы использовать это непосредственно в неизмененном виде, morteто будет работать только подход № 3.

Габриэль Гонсалес
источник
Как я вижу, мы не можем конвертировать # Bool₁ -> # Bool₂, не так ли?
ZeitRaffer
@ZeitRaffer Это верно. Вы не можете конвертировать из #Bool₁в#Bool₂
Габриэль Гонсалес
1
Хм ... IIUC вы называете "Исчисление индуктивных конструкций" исчислением с бесконечной иерархией типов, но AFAIK первоначальный CIC не имел такой вещи (он только добавлял индуктивные типы в CoC). Возможно, вы думаете о ECC Luo (расширенное исчисление конструкций)?
Стефан