问题描述
我正在尝试了解有关ocaml模块及其编译的具体事项:
I'm trying to understand a specific thing about ocaml modules and their compilation:
我被迫重新声明已在中声明的类型.mli
在特定的 .ml
实现中?
am I forced to redeclare types already declared in a .mli
inside the specific .ml
implementations?
举一个例子:
(* foo.mli *)
type foobar = Bool of bool | Float of float | Int of int
(* foo.ml *)
type baz = foobar option
根据我对接口/实现的常规思考方式,这应该没问题,但是它说
This, according to my normal way of thinking about interfaces/implementations, should be ok but it says
尝试编译时使用
ocamlc -c foo.mli
ocamlc -c foo.ml
当然,如果我在 foo.ml
中声明 foobar
,错误就会消失,但这似乎是一种复杂的方式,因为我有每次更改都要保持同步。
Of course the error disappears if I declare foobar
inside foo.ml
too but it seems a complex way since I have to keep things synched on every change.
有没有办法避免这种冗余,或者我每次都被迫重新声明类型?
Is there a way to avoid this redundancy or I'm forced to redeclare types every time?
提前致谢
推荐答案
OCaml试图强制你分开界面()( .ml
。大多数时候,这是一件好事;对于值,你发布的是typ e在界面中,并将代码保留在实现中。你可以说OCaml正在强制执行一定量的抽象(必须发布接口;接口中没有代码)。
OCaml tries to force you to separate the interface (.mli
) from the implementation (.ml
. Most of the time, this is a good thing; for values, you publish the type in the interface, and keep the code in the implementation. You could say that OCaml is enforcing a certain amount of abstraction (interfaces must be published; no code in interfaces).
对于类型,通常,实现是相同的作为接口:都声明该类型具有特定的表示(并且可能是类型声明是生成的)。这里,没有抽象,因为实现者没有关于他不想发布的类型的任何信息。 (例外情况基本上是在声明抽象类型时。)
For types, very often, the implementation is the same as the interface: both state that the type has a particular representation (and perhaps that the type declaration is generative). Here, there can be no abstraction, because the implementer doesn't have any information about the type that he doesn't want to publish. (The exception is basically when you declare an abstract type.)
查看它的一种方法是接口已经包含足够的信息来编写实现。给定接口类型foobar = bool of bool |飘浮浮动| Int of int
,只有一个可能的实现。所以不要编写实现!
One way to look at it is that the interface already contains enough information to write the implementation. Given the interface type foobar = Bool of bool | Float of float | Int of int
, there is only one possible implementation. So don't write an implementation!
一个常见的习惯用法是拥有一个专用于声明类型的模块,并使其只有 .mli
。由于类型不依赖于值,因此该模块通常在依赖链中很早就出现。大多数编译工具都能很好地应对这种情况;例如 ocamldep
将做正确的事情。 (与只有 .ml
相比,这是一个优势。)
A common idiom is to have a module that is dedicated to type declarations, and make it have only a .mli
. Since types don't depend on values, this module typically comes in very early in the dependency chain. Most compilation tools cope well with this; for example ocamldep
will do the right thing. (This is one advantage over having only a .ml
.)
这种方法的局限性在于你也这里和那里需要一些模块定义。 (一个典型的例子是定义类型 foo
,然后是 OrderedFoo:Map.OrderedType
模块,其中包含键入t = foo
,然后是另一个涉及的类型声明'一个Map.Make(OrderedFoo).t
。)这些不能放在接口文件中。有时将你的定义分解成几个块是可以接受的,首先是一堆类型( types1.mli
),然后是一个模块( mod1.mli
和 mod1.ml
),然后是更多类型( types2.mli
)。其他时候(例如,如果定义是递归的),您必须使用 .ml
而不使用 .mli
或重复。
The limitation of this approach is when you also need a few module definitions here and there. (A typical example is defining a type foo
, then an OrderedFoo : Map.OrderedType
module with type t = foo
, then a further type declaration involving'a Map.Make(OrderedFoo).t
.) These can't be put in interface files. Sometimes it's acceptable to break down your definitions into several chunks, first a bunch of types (types1.mli
), then a module (mod1.mli
and mod1.ml
), then more types (types2.mli
). Other times (for example if the definitions are recursive) you have to live with either a .ml
without a .mli
or duplication.
这篇关于OCaml类型声明中的冗余(ml / mli)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!