Types 使用显式类型将对象中方法的可见性限制为定义它的模块

Types 使用显式类型将对象中方法的可见性限制为定义它的模块,types,ocaml,Types,Ocaml,我在OCaml中有一个坐标“类”(使用一个返回对象文本的工厂函数实现),我正在试图找出如何将该对象上的方法的可见性限制在它在其中定义的模块上 这是源文件 (* coordinate.ml *) type coordinate = < get_x : int; get_y : int > let create_coord ~x ~y = object val x = x val y = y method get_x = x method get_y = y (*

我在OCaml中有一个坐标“类”(使用一个返回对象文本的工厂函数实现),我正在试图找出如何将该对象上的方法的可见性限制在它在其中定义的模块上

这是源文件

(* coordinate.ml *)
type coordinate = < get_x : int; get_y : int >

let create_coord ~x ~y = object
  val x = x
  val y = y
  method get_x = x
  method get_y = y
  (* hide this method from public interface *)
  method debug_print = Printf.printf "(x=%d, y=%d)\n"
end

有没有一种方法可以限制
debug\u print
坐标
之外的可见性,同时使其在内部自由访问?

您可以通过显式强制执行部分操作。一个简单的例子:

type t = < x : int; y : int >
let make x y : t =
  let o =
    object
      method x = x
      method y = y
      method z = `Not_exposed
    end
  in
  (o :> t)

(* val make : int -> int -> t = <fun> *)
但是这将不允许您公开
f
因为
t->unit
因为
t
没有
z
方法

您还可以公开两种类型,将完整对象类型抽象保持在模块上下文之外,并提供一个函数强制/转换为公开的、更受限制的类型:

module M : sig
  type t = < x : int; y : int >
  type opaque

  val make : int -> int -> opaque

  val f : opaque -> unit

  val of_opaque : opaque -> t
end = struct
  type t = < x : int; y : int >
  type opaque = < t; z : [`Not_exposed] >

  let make x y = object
    method x = x
    method y = y
    method z = `Not_exposed
  end

  let f (o : opaque) =
    assert (o#z = `Not_exposed)

  let of_opaque (o : opaque) : t =
    (o :> t)
end
模块M:sig
类型t=
类型不透明
val make:int->int->不透明
val f:不透明->单位
不透明值:不透明->t
end=struct
类型t=
类型不透明=
设x=y=object
方法x=x
方法y=y
方法z=`Not_exposed
结束
设f(o:不透明)=
断言(o#z=`Not#u exposed)
设_不透明(o:不透明):t=
(o:>t)
结束

我认为最好的解决方案是使用私有行类型:

module M : sig
  type t = private < x : int; y : int; .. >
  val make : int -> int -> t
  val f: t -> unit
end = struct
  type t = < x : int; y : int; z : [`Not_exposed] >

  let make x y = object
    method x = x
    method y = y
    method z = `Not_exposed
  end

  let f o =
    (* Access a method not exposed outside of the module *)
    assert (o#z = `Not_exposed)
end;;
模块M:sig
类型t=私有
val make:int->int->t
val f:t->单位
end=struct
类型t=
设x=y=object
方法x=x
方法y=y
方法z=`Not_exposed
结束
让我们=
(*访问未暴露在模块外的方法*)
断言(o#z=`Not#u exposed)
完;;;

这样,就不需要任何强制函数。尽管如此,
t
类型的任何对象都可以在模块M内看到其私有方法,但只有公共方法(
x
y
)可以在模块外访问。在。

中查找更多信息对于后代,我发现可以使用显式多态类型和显式向上转换来说服OCaml“忘记”方法是可以的

type kata = < foo : int; bar : string >
type ana = < foo : int >

let to_ana (k : < foo : int ; .. >) : ana = (k :> ana)

我认为这也限制了
坐标
模块内部的可见性。我仍然希望能够对使用模块内的
make
/
create\u-coord
创建的对象调用
debug\u-print
。为了做到这一点,我需要两个函数。。。一个未导出且未使用
:>t
,另一个已导出且使用
:t
?编辑了一些更新-简而言之,是的!在相应的
mli
文件中,
to_ana
的类型是什么?我不知道如何很好地使用
mli
文件。我认为关键是为ana的参数提供一个开放的对象类型,带有
,这样类型检查器就知道使用额外的方法可以获得更广泛的对象。
module M : sig
  type t = < x : int; y : int >
  type opaque

  val make : int -> int -> opaque

  val f : opaque -> unit

  val of_opaque : opaque -> t
end = struct
  type t = < x : int; y : int >
  type opaque = < t; z : [`Not_exposed] >

  let make x y = object
    method x = x
    method y = y
    method z = `Not_exposed
  end

  let f (o : opaque) =
    assert (o#z = `Not_exposed)

  let of_opaque (o : opaque) : t =
    (o :> t)
end
module M : sig
  type t = private < x : int; y : int; .. >
  val make : int -> int -> t
  val f: t -> unit
end = struct
  type t = < x : int; y : int; z : [`Not_exposed] >

  let make x y = object
    method x = x
    method y = y
    method z = `Not_exposed
  end

  let f o =
    (* Access a method not exposed outside of the module *)
    assert (o#z = `Not_exposed)
end;;
type kata = < foo : int; bar : string >
type ana = < foo : int >

let to_ana (k : < foo : int ; .. >) : ana = (k :> ana)
to_ana (object method foo = 42 method bar = "asdf" method baz = [] end)