从属类型理论和“任意”类型函数
我对这个问题的第一个答案是概念高而细节低,并反映在子问题“发生了什么?”;这个答案将是相同的,但侧重于子问题“我们能否获得任意类型的函数?”。
sum和product的代数运算的一种扩展是所谓的“大算子”,它表示通常分别写Σ
和Π
分别表示的序列的sum和积(或更一般地,一个域上的函数的sum和积)。请参阅Sigma符号。
所以总和
a₀ + a₁X + a₂X² + ...
可能会写
Σ[i ∈ ℕ]aᵢXⁱ
例如,哪里a
是实数序列。该产品将类似地以Π
代替Σ
。
当从远处看时,这种表达看起来很像;中的“任意”函数X
。当然,我们仅限于可表达的级数及其关联的分析功能。这是类型理论表述的候选人吗?绝对!
具有这些表达式的直接表示形式的类型理论类别是“从属”类型理论类别:具有从属类型的理论。自然地,我们有术语依赖于术语,并且在像Haskell这样的语言中具有类型函数和类型量化,术语和类型取决于类型。在从属设置中,我们还根据术语具有类型。Haskell不是依赖类型的语言,尽管可以通过稍微折磨该语言来模拟依赖类型的许多功能。
咖喱霍华德和从属类型
“柯里·霍华德同构”的诞生是因为观察到简单类型的lambda演算的术语和类型判断规则完全与应用于直觉命题逻辑的自然推论(由Gentzen公式化)相对应,其中类型代替了命题,并且术语代替了证明,尽管两者是独立发明/发现的。从那时起,它一直是类型理论家的巨大灵感来源。要考虑的最明显的事情之一是,命题逻辑的这种对应关系是否以及如何扩展到谓词逻辑或高阶逻辑。依赖类型理论最初是从这种探索途径产生的。
有关简单类型的lambda演算的Curry-Howard同构的介绍,请参见此处。例如,如果我们想证明,A ∧ B
就必须证明A
和证明B
;组合证明只是一对证明:每个合取项一个。
自然推论:
Γ ⊢ A Γ ⊢ B
Γ ⊢ A ∧ B
在简单类型的lambda演算中:
Γ ⊢ a : A Γ ⊢ b : B
Γ ⊢ (a, b) : A × B
对于∨
和和类型,→
函数类型以及各种消除规则也存在类似的对应关系。
不可证明的(直觉上是错误的)命题对应于一个无人居住的类型。
考虑到作为逻辑命题的类型的类比,我们可以开始考虑如何在类型世界中对谓词建模。有许多方法在此已正式(见本介绍马丁- LOF的直觉类型论为一种广泛使用的标准),但抽象的方法通常观察到的谓词就像是一个命题,免费长期变量,或者,一种对命题使用术语的功能。如果我们允许类型表达式包含项,则以lambda演算风格进行处理会立即成为一种可能!
仅考虑构造性证明,什么构成证明∀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
in中的每个X
,这都会提供|P(x)|
“选择”输出。
重点是
|∀x : X.P(x)| = Π[x : X]|P(x)|
如果X
is 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
是-type值的长度n
向量的X
类型。
从技术上讲,n
此处是自然数在系统中的表示,而不是实际的自然数。我们可以Nat
用Peano风格将自然数()表示为另一个自然数的零(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ⁿ
这样我们就可以将任意系数应用于幂级数。
我们已经了解了代数类型与数字的对应关系,从而使我们能够将类型映射为数字,并将类型函数映射为数值函数。我们也可以走另一条路!-取一个自然数,显然存在一个可定义的代数类型,其中有许多项成员,无论我们是否具有从属类型。我们可以通过归纳轻松地在类型理论之外证明这一点。我们需要的是一种在系统内部将自然数映射为类型的方法。
一个令人愉悦的认识是,一旦有了依赖类型,归纳证明和递归证明就变得极为相似-实际上,它们在许多理论中都是相同的。既然我们可以通过归纳证明存在满足我们需求的类型,那么我们是否应该不能构造它们呢?
有几种方法可以在术语级别表示类型。在这里,我将使用虚构的Haskellish表示法来表示*
类型的宇宙,通常将其本身视为从属环境中的类型。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)
或者在这种情况下这种否定和非整数“类型”可能具有什么意义。
希望这个答案对探索任意类型的函数可以走多远有所帮助。