Ocaml 在.mli中公开变量构造函数

Ocaml 在.mli中公开变量构造函数,ocaml,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中的变量构造函数?something.mli文件提供

考虑
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
中的变量构造函数?

something.mli文件提供了something.ml文件的接口。因此,您希望在接口中可见的任何内容都必须在something.mli中定义

因为您希望
这个
那个
可见,所以必须在something.mli中定义它们

对于您的小示例,something.mli将完全包含您在上面为something.ml显示的内容:

type some_type = This | That

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

something.mli文件提供了something.ml文件的接口。因此,您希望在接口中可见的任何内容都必须在something.mli中定义

因为您希望
这个
那个
可见,所以必须在something.mli中定义它们

对于您的小示例,something.mli将完全包含您在上面为something.ml显示的内容:

type some_type = This | That

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

.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>
# 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>

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

.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>
# 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>

这确保了t类型的值只能使用make函数构造。任何期望t类型的对象都只接受由make构造的t类型的值。另一方面,任何期望int类型的值也将接受t类型的值。对于抽象类型,后者就不适用了。

这是一个非常有用的答案——我个人完全忘记了
private
变体。答案中没有提到,但值得注意的是,这样做的目的是允许消费者在不允许构建变量类型的情况下对变量类型进行模式匹配。这是一个非常有用的答案-我个人完全忘记了
私有
变量。答案中没有提到,但值得注意的是,这样做的目的是允许用户对变体类型进行模式匹配,而不允许构造它。