我一直在研究OCaml对象系统并进行一般的输入。最近,我一直在使用多态变体和对象,并且在使类型系统执行我想要的工作时遇到了一些麻烦。
这就是我要做的事,很有意义
给出一些类型和函数定义:
type variant1 = [`Type1 | `Type2]
type variant2 = [`Type1 | `Type3]
type func1 = variant1 -> unit
type func2 = variant2 -> unit
let f1 : func1 = fun _ -> ()
let f2 : func2 = fun _ -> ()
(* Fails, but makes sense *)
let f3 : [`Type1] -> unit = f1
(* Error: This expression has type func1 = [ `Type1 | `Type2 ] -> unit
but an expression was expected of type [ `Type1 ] -> unit
The second variant type does not allow tag(s) `Type2 *)
(* Works, and is what I'd expect *)
let f3 : [`Type1] -> unit = (f1 : [`Type1] -> unit)
到目前为止,这是有道理的,任何只需要使用Type1的函数都可以使用可以接受Type1 + Type2的函数。这主要适用于对象:
type obj1 = < f : variant1 -> unit >
type obj2 = < f : variant2 -> unit >
type obj3 = < f : [`Type1] -> unit >
let o1 : obj1 = object method f = f1 end
let o2 : obj2 = object method f = f2 end
let o3 : obj3 = o1 (* Fails *)
let o3 : obj3 = (o1 :> obj3) (* Works *)
但是,当对象类型具有需要强制的方法参数时,事情就会倒塌,我不确定如何说服编译器进行转换:
type obj1 = < f : (variant1 -> unit) -> unit >
type obj2 = < f : ([`Type1] -> unit) -> unit >
let o1 : obj1 = object method f p = () end
let o2 : obj2 = (o1 :> obj2) (* Fails *)
Error: Type obj1 = < f : func1 -> unit > is not a subtype of
obj2 = < f : ([ `Type1 ] -> unit) -> unit >
Type [ `Type1 ] -> unit is not a subtype of
func1 = [ `Type1 | `Type2 ] -> unit
The second variant type does not allow tag(s) `Type2
在我看来,将obj1类型强制转换为obj2类型似乎仍然有效。它是否正确?这可能吗?也许我误会了什么?
答案 0 :(得分:4)
您的问题是子类型关系的方向相反:
let obj2 : obj2 = object method f p = p `Type1 end
let o3 = (o2 : obj2 :> obj1);;
因为函数与其参数是相反的。
要了解原因,请考虑以下类型为obj1
的特定值:
let o1 : obj1 = object method f p = p `Type1; p `Type2 end;;
如果我可以将无法处理`Type2
的函数发送到o1
,它将失败。因此,obj1
不是obj2
的子类型。相反,类型为obj2
的对象承诺仅使用`Type1
上的函数参数,因此将它们用作obj1
并不成问题,因为它们将始终接收可以处理更多内容的函数参数。比`Type1
。