我正在阅读OCaml首席设计师1994年关于模块,类型和单独编译的论文.(诺曼拉姆齐在另一个问题中向我指出).据我所知,本文讨论了OCaml目前的模块类型/签名系统的起源.在此,作者提出了对签名中类型声明的不透明解释(允许单独编译)以及清单类型声明(表达性).试图将我自己的一些示例放在一起来演示OCaml模块签名符号试图解决的问题,我在两个文件中编写了以下代码:
在文件中ordering.ml(或.mli- 我已经尝试过)(文件A):
module type ORDERING = sig
type t
val isLess : t -> t -> bool
end
Run Code Online (Sandbox Code Playgroud)
并在文件useOrdering.ml(文件B)中:
open Ordering
module StringOrdering : ORDERING
let main () =
Printf.printf "%b" StringOrdering.isLess "a" "b"
main ()
Run Code Online (Sandbox Code Playgroud)
想法是期望编译器抱怨(在编译第二个文件时)模块上没有足够的类型信息StringOrdering来检查StringOrdering.isLess应用程序(从而激发对with type语法的需求).但是,尽管文件A按预期编译,但文件B导致3.11.2 ocamlc抱怨语法错误.我知道签名的目的是允许某人根据模块签名编写代码,而无需访问实现(模块结构).
我承认我不确定语法:module A : B我在这篇相当旧的论文中遇到的单独编译,但它让我想知道是否存在这样或类似的语法(不涉及仿函数)以允许某人仅根据模块类型编写代码,在链接时提供的实际模块结构,类似于人们如何在C/C++中使用*.h和*.c文件.没有这样的能力,似乎模块类型/签名基本上用于密封/隐藏模块的内部或更明确的类型检查/注释,但不用于单独/独立的编译.
实际上,看看关于模块和单独编译的OCaml手册部分,似乎我对C编译单元的类比被打破了,因为OCaml手册将OCaml编译单元定义为A.ml和A.mli二重奏,而在C/C++中,.h文件被粘贴到任何导入.c文件的编译单元.
做这样的事情的正确方法是执行以下操作:
在ordering.mli写道:
(* This define the signature *)
module type ORDERING = sig
type t
val isLess : t -> t -> bool
end
(* This define a module having ORDERING as signature *)
module StringOrdering : ORDERING
Run Code Online (Sandbox Code Playgroud)编译文件: ocamlc -c ordering.mli
在另一个文件中,请参阅编译的签名:
open Ordering
let main () =
Printf.printf "%b" (StringOrdering.isLess "a" "b")
let () = main ()
Run Code Online (Sandbox Code Playgroud)
编译文件时,会得到预期的类型错误(即string不兼容Ordering.StringOrdering.t).如果要删除类型错误,则应将with type t = string约束添加到StringOrderingin 的定义中ordering.mli.
所以回答第二个问题:是的,在字节码模式下,编译器只需要知道你所依赖的接口,你可以选择在链接时使用哪个实现.默认情况下,本地代码编译不适用(因为模块间优化),但您可以禁用它.