“System Fω在System F的显式类型多态上加入高阶类型算子。它的“高阶”首先发生在类型层:类型函数可以接收另一个类型函数,项也能对这种类型函数量化。”
形式陈述
Kind为类型表达式分类,区分“完整的值类型”和“还要接收类型参数的算子”。本页采用最简单的kind语言:
像项的类型判断一样,类型层有判断
固定常量Int、Bool、List、Pair,其中
List和Pair在这里是给定类型构造器,不需要展开它们的数据定义。类型层还允许抽象与应用,主要规则为
项函数类型 Pair Int Bool 是 (Pair Int) Bool。
直觉
把List想成一个留有空格的类型模板。填入Int得到整数列表,填入Bool得到布尔列表。List本身还没说元素是什么,因而不能在这个系统里直接写一个普通变量声明 xs:List。
Pair留有两个空格。先填Int得到 Pair Int:*→*,还可以再填Bool得到 Pair Int Bool:*。部分应用没有失败,只是结果仍是类型算子。
类型层的λ与λ演算形式相似,不过参数是类型表达式而不是运行时整数或函数值。λX:*.Pair X Bool描述“把X与Bool配成一对”的类型变换;它没有分配一个二元组,也没有创建一个运行时闭包。
例子与边界
一个接收类型算子的算子
考虑
逐步检查:在
于是K List合法,结果是List Int。K (Pair Bool)也合法,结果是Pair Bool Int。K Int则不合法,因为K要求的实参kind是
下面四个判断把“尚未填完”与“填错位置”分开:
| 表达式 | 结果 | 理由 |
|---|---|---|
| Pair Int | 合法部分应用 | |
| List (Pair Int Bool) | List收到完整二元组类型 | |
| List List | 拒绝 | 实参List不是 |
| Int Bool | 拒绝 | Int没有函数kind,不能应用 |
List Int和List Bool的kind相同,类型却不同。Kind检查只保证类型表达式的接口匹配,不把同一kind内的所有类型判作相等;正如3和true都能出现于程序中,也不能据此认为它们类型相同。
三层对象不要互换
3:Int是项判断,Int:*是类型表达式的kind判断。这里的
本页只允许类型依赖类型,类型算子不能读取一个普通项变量n来计算“长度恰为n的数组类型”。那需要另行加入依赖项的类型规则。Kind与依赖类型中的宇宙也有联系,但简单箭头kind分类并不包含宇宙提升、累积性或 Type_i:Type_{i+1} 的规则,不能只凭“类型的类型”这句口号混用两套体系。
推论与应用
Kind检查可以按类型表达式的语法树递归执行:变量查Δ,应用先检查函数kind再比较参数kind,抽象扩展Δ。每一步下降到严格子表达式,因此对本页有限语法总会结束。检查器遇到 List List 时能在类型层报错,不必等待项级检查才发现问题。
System F只对普通类型量化;若还允许项在
一个实用自检是:对每个类型参数同时写出名字和kind。若接口接收的是List,就写
参考资料
- Mark P. Jones, Typing Haskell in Haskell, 2000,§3:基本kind与类型构造器
- Andrew M. Pitts, Lecture Notes on Types, 2015,§5.3:高阶类型构造与Fω
- Benjamin C. Pierce, Types and Programming Languages, MIT Press, 2002,Chapter 29:类型算子