OCaml 中的受保护方法
摘要
本文解释了如何使用类型相等性证明在 OCaml 中编码受保护方法,从而仅对特定方法而非整个类施加接收者约束。
<p><a href="https://lobste.rs/s/ki0ge3/guarded_methods_ocaml">评论</a></p>
查看缓存全文
缓存时间: 2026/08/03 01:33
# OCaml 中的守卫方法
来源:https://xvw.lol/en/articles/oop-refl.html
**守卫方法(Guarded methods)**允许你仅针对某些方法向接收者(`self`)附加**约束**,这意味着这些方法只有在接收者满足这些约束(即*守卫*)时才能被调用。
OCaml (https://ocaml.org/) 在语法层面并不允许*直接*定义这类方法。在本文中,我们将探讨如何利用**类型相等见证(type equality witness)**来对它们进行编码。
## 问题描述
当一门语言(在程序运行前进行类型检查,如 Java 或 OCaml)引入**参数多态**(Java 的*泛型*)时,有时可以约束类型变量。例如:
```
class MyClass { ... }
```
我们假设类型变量 `T` 是 `S` 的子类型,从而让 `MyClass` 变得可泛型。问题在于,这种约束应用于**整个类**。但有时我们希望约束只应用于**某些特定方法**。
例如,假设我们有一个描述列表的类 `MyList`:
```
class MyList extends ArrayList {
public int length() { return this.size(); }
}
```
我们如何定义一个 `flatten` 方法,使得对于类似 `[[1, 2, 3], [4, 5]]` 的列表,能生成 `[1, 2, 3, 4, 5]`?如果将约束放在类级别,我们就会强制这个列表“*始终是列表的列表*”,这非常受限。要实现这样的方法,我们有三种理论上的途径。
### 将方法移到类外部
第一种解决方案最明显:简单地“*作弊*”,把方法移到类体之外(例如,放入静态上下文或*伴生对象*中):
```
class MyList extends ArrayList {
public static MyList flatten(MyList> list) {
// flatten 的实现
}
public int length() { return this.size(); }
}
```
这种方法有效,而且不需要任何特殊仪式。但它迫使开发者去跟踪哪些方法在类体中、哪些在静态上下文中。此外,它破坏了向实例发送消息的系统性方式(这常常被作为支持面向对象编程的关键论据之一)。
### 扩展方法
Kotlin (https://kotlinlang.org/)(以及其他语言,如 C# (https://docs.microsoft.com/en-us/dotnet/csharp/))提供了扩展方法 (https://kotlinlang.org/docs/extensions.html)。这些扩展方法除了允许**扩展现有类**(这对于为 `String` 类(在 Java 中是 `final` 的)添加行为非常有用)之外,在定义*接收者*方面也提供了更大的灵活性。例如,我们可以用如下的方式(在 Kotlin 中)编写 `flatten`:
```
class MyList : ArrayList {
...
}
fun MyList>.flatten() = ...
```
尽管这个方案看起来近乎完美,但它仍然要求方法在**类外部**定义,这可能意味着必须将类的某些成员设为*公有(public)*才能从扩展中访问(看起来存在潜在的*抽象泄漏*)。不过,它仍然**保留了系统性的消息发送方式,同时允许更细粒度地限定接收者**。
###
相似文章
卫兵!卫兵
探讨 Elixir 中一个令人惊讶的行为:`is_map_key/2` 守卫可能导致守卫失败而非返回 false,从而破坏了布尔运算符的可交换性。
OxCaml 中其他语言应该借鉴的功能 - The Consensus
OxCaml 是 Jane Street 的 OCaml 超集,引入了一个 `[@zero_alloc]` 注解,强制编译器在调用树中任何函数在堆上分配内存时拒绝构建,将内存分配检测从运行时分析转变为编译时强制执行。
OxCaml 中的数据竞态自由
OxCaml 是 Jane Street 对 OCaml 编译器的分支,它引入了编译时对数据竞态的保证,从而在不增加运行时开销的情况下实现顺序一致性。这篇博文解释了新的模式轴及其对并行编程的影响。
Dart中的证明类型:使用final类作为计算见证
本文解释了如何使用Dart的带有私有构造函数的final类来创建证明类型,这些类型在编译时强制执行验证,确保在使用值之前已经执行了某些计算。
类型推断(第一部分)
关于类型推断的教程,涵盖Damas-Hindley-Milner类型系统、合一及相关概念,并附有OCaml代码示例。