在.mli

时间:2019-01-30 05:14:55

标签: ocaml

考虑something.ml

type some_type =
  | This
  | That

然后,我可以像这样实现main.ml

let x = Something.This

我想创建something.mli并在main.ml中保留相同的功能。我的第一次尝试是将something.mli编写为:

type some_type

我认为这将使变体构造函数公开可用,但现在没有main.ml可以编译。有没有办法在.mli中公开变体构造函数?

2 个答案:

答案 0 :(得分:1)

something.mli文件提供了something.ml文件的界面。因此,您想要在界面中显示的任何内容都必须在something.mli中定义。

由于您希望ThisThat可见,因此必须在something.mli中对其进行定义。

举个小例子,something.mli会完全包含上面对something.ml显示的内容:

type some_type = This | That

当然,在一个更现实的示例中,该接口所包含的内容要比实现少得多。特别是它只具有公共功能的类型,而没有代码。

答案 1 :(得分:1)

.mli文件自己定义模块的接口,并且在编译它们时根本不使用.ml文件。实际上,对于由多个.ml文件组成的数据包,实际上可以有一个.mli文件。永远不会神奇地将.ml文件中的内容拖到界面中。

现在,与.ml文件中的内容相同,有三种方法可以在.ml文件中指定类型:

1)作为抽象类型。没有暴露出以下类型的东西:

# type some_type;;
type some_type
# let v = This;;   
Error: Unbound constructor This
# let to_int = function This -> 1 | That -> 2;;
Error: Unbound constructor This

这从外部隐藏了类型的详细信息,允许模块稍后随意更改类型而不会破坏任何源代码。它也用于没有值或非ocaml类型的外部值(请参见手册中的C)的幻像类型。

2)作为公共类型。该类型的结构是公开的,可以创建值:

# type some_type = This | That;;
type some_type = This | That
# let v = This;;
val v : some_type = This
# let to_int = function This -> 1 | That -> 2;;
val to_int : some_type -> int = <fun>

这与第一种情况相反。一切都公开了。

但是还有第三种选择:

3)作为私有类型。该类型的结构已公开,但无法创建值:

# type some_type = private This | That;;
type some_type = private This | That
# let v = This;;
Error: Cannot create values of the private type some_type
# let to_int = function This -> 1 | That -> 2;;
val to_int : some_type -> int = <fun>

这在1到2之间。此用例是当您需要控制值的构造时。例如,假设一个类型包含小于100的小整数。您应该这样写:

# let make x =
      if x < 0 || x >= 100
          then raise (Invalid_argument "Out of range")
          else x;;
val make : int -> int = <fun>

然后,您将.mli文件写为:

type t = private int;;
val make : int -> t;;

这确保了只能使用make函数构造类型t的值。期望类型t的任何内容都只会接受由make构造的类型t的值。另一方面,任何期望类型为int的东西也将接受类型t的值。后者不是抽象类型的情况。