从多个模块创建库时,我无法找到一种很好的方法来隐藏到库的用户(外部接口),同时能够访问内部接口上所需的所有内容。
更具体地说,我有两个模块(文件a.ml [i]和b.ml [i])。在A中,我定义了一些类型t,这是我不想向用户隐藏的内部结构(外部接口)。
module A : sig
type t
end
module A = struct
type t = float
end
在模块B中,我想使用A.t
的秘密类型。
module B : sig
create_a : float -> A.t
end
module B = struct
create_a x = x
end
这当然不能编译,因为B的编译单元不知道A.t
的类型。
我知道的解决方案,但不喜欢:
create_a
移至模块A
A.t
的定义复制到B
,并使用某些external cheat : `a -> `b = "%identity"
是否有其他方法可以在A.t
中了解B
的类型,而不会将此信息泄露给图书馆的界面?
答案 0 :(得分:3)
一如既往,额外的间接层可以解决这个问题。定义将指定外部接口的模块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
如果您不想重复自己并且两次编写模块签名,那么您可以在模块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
最后,确保您没有安装接口(.cmi
文件),
在安装步骤中,用户无法绕过您的抽象。如果你正在使用绿洲,那么它很简单:只需将所有模块放在内部,模块Lib
除外,即用InternalModules
字段指定它们。