OCaml 中的外部和内部接口和信息隐藏

lam*_*wer 4 ocaml module

当从多个模块创建一个库时,我找不到一种很好的方法来向库的用户(外部接口)隐藏正确的信息,同时能够在内部接口上访问我需要的一切。

更具体地说,我有两个模块(文件 a.ml[i] 和 b.ml[i])。在 A 中,我定义了一些类型 t,这是我不想向用户隐藏的内部结构(外部接口)。

module A : sig
  type t
end
module A = struct
  type t = float
end
Run Code Online (Sandbox Code Playgroud)

在模块B,然后我想用秘密类型A.t

module B : sig
  create_a : float -> A.t
end
module B = struct
  create_a x = x
end
Run Code Online (Sandbox Code Playgroud)

这当然不会编译,因为 B 的编译单元不知道A.t.

我知道但不喜欢的解决方案:

  1. 将功能create_a移至模块A
  2. 复制A.tto的定义B并用一些欺骗类型检查器external cheat : `a -> `b = "%identity"

有没有其他方法可以A.tB不将此信息泄漏到图书馆界面的情况下了解in的类型?

ivg*_*ivg 5

一如既往,额外的间接层可以解决这个问题。定义一个Lib将指定外部接口的模块,例如,

module Lib : sig 
 module A : sig
   type t
   (* public interface *)
 end
 module B : sig 
    type t 
    (* public interface *)
 end = struct 
   module A = A
   module B = B
 end
Run Code Online (Sandbox Code Playgroud)

如果您不想重复自己并编写两次模块签名,那么您可以在一个模块中定义一次sigs.ml

 module Sigs = struct
   module type A = sig 
     type t
     (* public interface *)
   end

   (* alternatively, you can move it into sigs_priv.ml *)
   module type A_private = sig 
     include A
     val create_a : float -> t
   end

   ...
 end
Run Code Online (Sandbox Code Playgroud)

最后,确保.cmi在安装步骤中您没有安装接口(文件),以便用户无法绕过您的抽象。如果您正在使用 oasis,那么这很简单:只需将所有模块内置于内部,除了 module Lib,即,使用InternalModules字段指定它们。