PTS / CoC中教会编码类型的从属类型


11

我正在Barendregt的lambda多维数据集中尝试使用纯类型系统,特别是最强大的系统,即构造微积分。该系统具有排序*BOX。仅出于记录目的,下面我使用Morte工具https://github.com/Gabriel439/Haskell-Morte-Library的具体语法,该语法与经典的lambda演算很接近。

我看到我们可以通过某种类似于教堂的编码(对于代数数据类型也称为Boehm-Berarducci同构)来模拟归纳类型。作为一个简单的示例,我将type Bool = ∀(t : *) -> t -> t -> t与构造函数True = λ(t : *) -> λ(x : t) -> λ(y : t) -> xand一起使用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 TrueD False。有没有D再次创建的规范方法?我想Bool -> T = Product T T通过if类型级别的函数的类似物来重现同构,但if由于我们无法在类型之类的参数中传递类型,因此我无法像原始函数那样编写此函数。

  2. 我使用一种具有两个构造函数的归纳类型来解决问题(1)。高级描述(Agda样式)是以下类型(用于代替type-level 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


Product T TBoolTBoolT((t:)(ttt))TProductTT(t:)((TTt)t)

@Giorgio Mossa参见cstheory.stackexchange.com/questions/30923/…-如果您具有参数性(并非在所有模型中,但在最初的(句法)模型中),则您具有同构性。
ZeitRaffer

Answers:


9

您无法使用传统的Church编码执行以下操作Bool

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

...因为您无法编写以下类型的(有用)函数:

#Bool → *

正如您所指出的,原因是您不能将*第一个参数传递给#Bool,这又意味着TrueFalse参数可能不是类型。

至少有三种方法可以解决此问题:

  1. 使用归纳构造微积分。然后,您可以将的类型概括#Bool为:

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

    ...然后实例化n1,这意味着您可以*₀作为第二个参数传入,这将进行类型检查,因为:

    *₀ : *₁
    

    ...因此您可以#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添加了归纳类型)。您可能会想到Luo的ECC(扩展的结构演算)?
Stefan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.