我正在研究一种新的编程语言的想法,理想情况下我希望这种语言能够混合一些功能和程序(面向对象)的概念。
我对Haskell这样的语言非常着迷的一个原因是它是静态类型的,但你不需要注释类型(魔术感谢Hindley-Milner!)。
对于我的语言,我真的很喜欢这个,但是在阅读了这个主题后,似乎大多数人认为类型推断对于子类型/面向对象是不切实际/不可能的,但是我不明白为什么会这样。我不知道F#,但我知道它使用Hindley-Milner并且是面向对象的。
我真的想要对此进行解释,并且最好是关于面向对象语言不可能进行类型推断的场景的示例。
当使用标称类型(这是一个打字系统,其中两个成员具有相同名称且相同类型的类不可互换)时,会有许多可能的类型,如下所示:
let f(obj) =
obj.x + obj.y
任何同时拥有成员的类 x
和一个成员 y
(支持的类型 +
运营商)将有资格作为可能的类型 obj
并且类型推断算法无法知道哪一个是你想要的那个。
在F#中,上面的代码需要一个类型注释。所以F#有面向对象和类型推断,但不能同时进行(局部类型推断除外)let myVar = expressionWhoseTypeIKNow
),总是有效的)。
添加到seppk的响应:对于结构对象类型,他描述的问题实际上消失了(f可以被赋予多态类型,如∀A&leq {x:Int,y:Int} .A→Int,或者甚至只是{x:Int ,y:Int}→Int)。但是,类型推断仍然存在问题。
根本原因在于:在没有子类型的语言中,键入规则强加 平等 对类型的约束。在类型检查期间处理这些非常好,因为通常可以使用类型的统一来立即简化它们。但是,通过子类型,这些约束被推广到 不等式 限制。你不能再使用统一,至少有三个不愉快的后果:
- 约束的数量和复杂性在组合上爆炸。
- 如果出现错误,您必须向用户显示的信息是不可理解的。
- 某些形式的量化很快就会变得不可判断。
因此,对于子类型的类型推断并非不可能(在90年代已经有很多关于这个主题的论文),但它不是很实用。
OCaml使用了一种更简单的替代方案,它使用所谓的方法 行多态性 代替子类型。这实际上是易处理的。