我想了解 OCAML 对象这种行为的原因。假设我有一个类A
调用另一个类的对象的方法B
。从原理上讲,A#f 调用 B#g 和 B#h。OOP 中的常规做法是我想避免将 B 用作固定的具体类,而是只为 B 声明一个接口。在 OCAML 中执行此操作的最佳方法是什么?我尝试了几个选项,但我不太明白为什么其中一些有效而另一些无效。以下是代码示例。
版本 1:
# class classA = object
method f b = b#g + b#h
end ;;
Error: Some type variables are unbound in this type:
class a : object method f : < g : int; h : int; .. > -> int end
The method f has type (< g : int; h : int; .. > as 'a) -> int where 'a
is unbound
这种行为是众所周知的:OCAML 正确推断出b
具有开放对象类型<g:int;h:int;..>
,但随后抱怨我的类没有声明任何类型变量。所以似乎需要classA
有类型变量;然后我明确地介绍了一个类型变量。
版本 2:
# class ['a] classA2 = object
method f (b:'a) = b#g + b#h
end ;;
class ['a] classA2 :
object constraint 'a = < g : int; h : int; .. > method f : 'a -> int end
这可行,但该类现在是具有类型约束的显式多态性,如 OCAML 所示。类类型包含类型变量也令人困惑,'a
但我仍然可以说let x = new classA2
没有为'a
. 为什么会这样?
另一个缺点classA2
是显式类型约束(b:'a)
包含类型变量。毕竟,我知道它b
必须符合一个固定的接口而不是一个未知的类型'a
。我希望 OCAML 验证这个接口确实是正确的。
所以在版本 3 中,我首先将接口声明classB
为类类型,然后声明它b
必须是这种类型:
# class type classB = object method g:int method h:int end;;
class type classB = object method g : int method h : int end
# class classA3 = object method f (b:classB) = b#g + b#h end;;
class classA3 : object method f : classB -> int end
这也有效,但我的困惑仍然存在:为什么不再classA3
需要显式多态性?
问题总结:
- 为什么即使使用类型变量声明也可以在
new classA2
不指定类型的情况下使用?'a
classA2
'a
- 为什么
classA3
接受类型约束(b:classB)
并且不再需要绑定类型变量? - 的功能是否存在某种微妙的
classA2
差异classA3
,如果是,如何?