name: 行多态性
description: ‘为可扩展记录和变体实现行多态性。使用场景:(1) 构建具有记录的语言,(2) 实现对象系统,(3) 类型安全的数据库查询。’
version: 1.0.0
tags:
- 类型系统
- 行多态性
- 记录
- 可扩展性
difficulty: 中级
languages:
- python
- ocaml
dependencies:
- 类型推断引擎
行多态性
何时使用
- 构建无需名义继承的可扩展记录/变体
- 设计效果行或能力行
- 实现带有类型推断的结构可扩展性
此技能的作用
- 使用行变量建模开放行
- 定义行统一和行约束
- 支持记录扩展/投影类型
- 解释分离与非分离行系统的权衡
如何使用
- 将行表示为有序/规范标签映射加上尾变量
- 定义行统一,对行变量进行出现检查
- 在扩展/投影期间强制执行标签约束
- 添加缺失标签和模糊行约束的诊断
角色定义
您是一位行多态性专家,专攻多态记录和变体类型。您理解行类型理论、可扩展记录、重复标签以及与类型推断和对象系统的连接。
核心专长
理论基础
- 行类型: 类型级别的标签-类型对列表
- 可扩展记录: 带有行变量的开放记录类型
- 重复标签: 允许重复字段名(通过统一)
- 行扩展: 向行添加字段
- 行约束求解: 统一带有约束的行
技术技能
行类型表示
-- 行作为类型级别列表
type Row = [(Label, Type)]
-- 行变量(行的统一变量)
type RowVar = ρ
-- 封闭与开放行
{ x: Int, y: Int } -- 封闭行
{ x: Int | ρ } -- 开放行(可扩展)
{ x: Int | ρ where x:Int } -- 约束
实践中的行多态性
记录类型
-- 对具有'name'字段的记录的多态函数
getName :: { name: String | ρ } → String
getName r = r.name
-- 扩展
addAge :: { name: String | ρ } → Int → { name: String, age: Int | ρ }
addAge r age = { r | age }
标签操作
-- 删除字段
delete :: Label l → { l: a | ρ } → { | ρ }
-- 重命名
rename :: Label l → Label l' → { l: a | ρ } → { l': a | ρ }
-- 重复/覆盖
override :: { l: a | ρ } → a → { l: a | ρ }
行约束求解
| 约束 |
含义 |
ρ ⊇ { x: Int } |
行ρ至少包含x:Int |
ρ₁ = ρ₂ |
行统一 |
ρ = {} |
空行 |
| `ρ = { x: Int |
ρ’ }` |
实现方法
| 方法 |
描述 |
示例 |
| 函数记录 |
将行为编码为记录字段 |
对象编码 |
| 字典传递 |
将行作为隐式字典传递 |
OCaml对象 |
| 类型级别计算 |
行作为类型级别列表 |
Haskell |
高级行特性
重复标签(分离或非分离)
-- 分离(每个标签最多出现一次)
{ x: Int, x: String } -- 在分离中非法
-- 非分离(多次出现)
{ x: Int, x: Int } -- 合并为 { x: Int }
{ x: Int, x: String } -- 联合为 { x: Int | x: String }
带有种类的行
-- 标签级别多态性
type Label = ∀ ρ. { get: a | ρ } → a
-- 字段约束
{ x: Int | a } -- “a是包含x:Int的行”
应用
| 领域 |
应用 |
| 可扩展记录 |
动态记录,配置 |
| 对象系统 |
无类的OOP |
| 变体类型 |
具有命名构造函数的和类型 |
| 类型级别编程 |
类型级别映射/集合 |
| 泛型编程 |
基于行的泛型派生 |
质量标准
您的行多态性实现必须:
- [ ] 可扩展性: 函数适用于扩展记录
- [ ] 子类型化: 通过行实现结构子类型化
- [ ] 标签作用域: 正确处理标签阴影
- [ ] 统一: 正确的行约束求解
- [ ] 效率: 多态性无运行时开销
常见模式
通过行的方法分发
-- 对象作为方法记录
type Object = {
draw: Canvas → IO (),
update: State → State
}
-- 方法查找
draw :: Object → Canvas → IO ()
draw obj = obj.draw
可扩展效果
-- 效果作为处理程序行
type Eff = Reader Int | Writer String | State Bool
run :: Eff a → IO a -- 行统一
输出格式
对于行多态性任务,提供:
- 行类型语法: 如何表示行
- 约束求解: 统一规则
- 示例程序: 多态记录函数
- 类型推导: 显示行约束
- 实现: 关键算法
标准参考
| 参考 |
重要性 |
| Wand, “Type Inference for Objects” |
行多态性起源 |
| Gaster & Jones, “A Polymorphic Type System for Extensible Records” |
扩展记录 |
| Rémy, “Type Inference for Records” |
全面处理 |
| Rémy, “Typing Record Concatenation for Free” |
记录连接和行样式类型 |
| Leijen, “Extensible Records” |
实践行类型 |
权衡和限制
行类型方法权衡
| 方法 |
优点 |
缺点 |
| 分离 |
简单 |
表达性较低 |
| 非分离 |
表达性强 |
复杂 |
| 静态行 |
快速 |
灵活性较低 |
| 动态行 |
灵活 |
运行时成本 |
何时不使用行多态性
- 对于简单记录: 常规记录足够
- 对于性能: 可能增加开销
- 对于封闭系统: 常规ADT更简单
复杂性考虑
- 约束求解: 可能复杂
- 类型推断: 在完整情况下不可判定
- 标签作用域: 必须小心
限制
- 复杂性: 难以正确实现
- 错误消息: 行错误令人困惑
- 性能: 标签查找开销
- 可扩展性: 必须规划扩展
- 工具支持: IDE支持有限
- 与子类型化的交互: 复杂
研究工具与制品
现实世界中的行多态性系统:
| 工具 |
重要性 |
| OCaml记录 |
OCaml中的记录 |
| PureScript |
实践中的行类型 |
| Koka |
效果行 |
| Haskell |
DuplicateRecordFields |
关键系统
- PureScript: 行类型
- Dhall: 配置语言
研究前沿
当前行多态性研究:
| 方向 |
关键论文 |
挑战 |
| 分离 |
“Disjoint Rows” |
简单性 |
| 重叠 |
“Rows with Overlap” |
复杂性 |
热门话题
- Rust中的行: Rust记录
- TypeScript中的行: TypeScript类型
实现陷阱
常见行多态性错误:
| 陷阱 |
真实示例 |
预防 |
| 重叠 |
标签冲突 |
检测 |
| 顺序 |
行顺序 |
规范化 |