首页 > 解决方案 > 如何在 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 + `Type2 的函数都应该能够在只需要 `Type1 的地方使用。这主要适用于对象:

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 类型似乎仍然有效。这个对吗?这可能吗?也许我误解了什么?

标签: ocaml

解决方案


您的问题是子类型关系朝相反的方向发展:

 let obj2 : obj2 = object method f p = p `Type1 end 
 let o3 = (o2 : obj2 :> obj1);;

因为函数相对于它们的论点是逆变的。

要了解原因,请考虑例如 type 的这个特定值obj1

 let o1 : obj1 = object method f p = p `Type1; p `Type2 end;;

如果我可以发送一个无法处理的函数,`Type2它将o1失败。因此,obj1不是 的子类型obj2。相反,对象类型obj2承诺只在 上使用函数参数`Type1,因此将它们用作 没有问题obj1,因为它们总是会收到可以处理超过 的函数参数`Type1


推荐阅读