Jac*_*ack 32 ocaml module interface declaration
我正在尝试理解关于ocaml模块及其编译的具体事项:
我是否被迫重新声明已在.mli特定.ml实现中声明的类型?
举个例子:
(* foo.mli *)
type foobar = Bool of bool | Float of float | Int of int
(* foo.ml *)
type baz = foobar option
Run Code Online (Sandbox Code Playgroud)
根据我对接口/实现的正常思考方式,这应该没问题,但它说
错误:未绑定的类型构造函数foobar
在尝试编译时
ocamlc -c foo.mli
ocamlc -c foo.ml
Run Code Online (Sandbox Code Playgroud)
当然,如果我申报错误消失foobar里面foo.ml太多,但它似乎是一个复杂的方式,因为我要保持同步的东西在每一个变化.
有没有办法避免这种冗余,或者我每次都被迫重新声明类型?
提前致谢
Nor*_*sey 18
是的,你被迫重新宣布类型.我知道的唯一方法是
不要使用.mli文件; 只是暴露一切没有界面.可怕的主意.
使用文字编程工具或其他预处理器来避免重复One True Source中的接口声明.对于大型项目,我们在我的小组中执行此操作.
对于小型项目,我们只需复制类型声明.并抱怨它.
Gil*_*il' 17
OCaml试图强制你将interface(.mli)与实现分开(.ml大多数时候,这是一件好事;对于值,你在界面中发布类型,并将代码保留在实现中.你可以这样说OCaml正在实施一定量的抽象(必须发布接口;接口中没有代码).
对于类型,通常,实现与接口相同:都声明类型具有特定表示(并且可能类型声明是生成的).这里,没有抽象,因为实现者没有关于他不想发布的类型的任何信息.(例外情况基本上是在声明抽象类型时.)
查看它的一种方法是接口已经包含足够的信息来编写实现.给定接口type foobar = Bool of bool | Float of float | Int of int,只有一种可能的实现.所以不要写一个实现!
一个常见的习惯用法是拥有一个专用于声明类型的模块,并使其只有一个.mli.由于类型不依赖于值,因此该模块通常在依赖链中很早就出现.大多数编译工具都能很好地应对这种情况; 例如,ocamldep会做正确的事情.(这比只有一个优势更有优势.ml.)
这种方法的局限性在于您还需要一些模块定义.(一个典型的例子是定义一个类型foo,然后是一个OrderedFoo : Map.OrderedType模块type t = foo,然后是另一个涉及的类型声明'a Map.Make(OrderedFoo).t.)这些不能放在接口文件中.有时将你的定义分解成几个块是可以接受的,首先是一堆类型(types1.mli),然后是一个模块(mod1.mli和mod1.ml),然后是更多类型(types2.mli).其他时候(例如,如果定义是递归的),您必须使用.ml没有.mli或重复的.
ane*_*eal 14
您可以让ocamlc从ml文件中为您生成mli文件:
ocamlc -i some.ml > some.mli
Run Code Online (Sandbox Code Playgroud)