如何在OCaml中强制对象参数

时间:2019-01-10 03:12:00

标签: ocaml

我一直在研究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类型似乎仍然有效。它是否正确?这可能吗?也许我误会了什么?

1 个答案:

答案 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