为何在SML中使用重载运算符定义函数未出现预期报错?
问题
我正在阅读Colin Myers、Chris Clack和Ellen Poon所著的《Programming with Standard ML》,在§2.4.1「受限多态函数」章节中提到:
与运算符
=和<>不同,>、<等其他比较运算符是重载的,它们并非受限多态,因此如下函数定义会失败:
- fun wrong_ordered (x, y, z) = (x < y) andalso (y < z); Error: overloaded variable "<" cannot be resolved
失败原因是SML无法确定x、y、z的类型。但我在SML/NJ 110.99.2和Poly/ML 5.9中输入该定义时未收到错误,定义成功并返回:
- fun wrong_ordered (x, y, z) = (x < y) andalso (y < z); val wrong_ordered = fn : int * int * int -> bool
请问为何未出现书中所述的报错?
解答
这是因为现代SML编译器(包括你使用的SML/NJ和Poly/ML)实现了重载类型的默认推断规则,而书中描述的是早期标准ML或更严格的编译器行为。
具体细节:
- 早期标准ML规范中,重载运算符(如
<、>)没有默认类型绑定,编译器无法自动推断未指定类型的重载变量类型,因此会抛出"overloaded variable cannot be resolved"的错误。 - 现代编译器为提升易用性,给重载的数值比较运算符添加了默认类型——
int。当编译器无法从上下文推断出具体类型时,会自动将这些重载运算符绑定到int类型,所以你的函数会被推断为接受int * int * int参数并返回bool,不会报错。
你可以验证这一点:显式指定非int类型时,编译器会正确推断对应类型,比如:
fun wrong_ordered (x: real, y: real, z: real) = (x < y) andalso (y < z);
此时函数类型会被推断为real * real * real -> bool,无任何问题。只有当没有上下文或显式类型标注时,现代编译器才会默认用int解析重载的比较运算符。
内容的提问来源于stack exchange,提问作者Flux
相关产品推荐
相关产品推荐

