我正在将 SML 起始代码从 Tiger 书转换为 OCaml。
让我感到困惑的是,在签名文件table.sig
(下图(中,没有提到IntMapTable
,但函子可以在另一个文件中访问,无需任何限定。
(* table.sig *)
signature TABLE =
sig
...
end
(* table.sml *)
functor IntMapTable (...) : TABLE =
struct
...
end
(* symbol.sml *)
...
structure Table = IntMapTable(...)
...
我的理解是,只有.sig
文件中的代码可以访问外部模块,而不能访问.sml
文件中的代码。难道不是这样吗?
另外,OCaml 中的等效代码可能是什么样子的?这很尴尬,因为函子IntMapTable
的结果类型是 Table
,这是文件的封闭模块。
对于 SML,文件及其名称都没有多大意义。它们只是将较大的来源切成更小单元的一种方式。由多个文件组成的程序等效于以某种合适的顺序连接这些文件。
这在 OCaml 中有所不同,其中每个 .ml 文件本身都被视为从文件名派生的名称的结构,而每个关联的 .mli 文件(如果存在(都被视为该结构上的不透明签名批注。
(Moscow ML基于OCaml运行时的早期实现,是使用类似文件模型的SML实现。
因此,将 SML 文件移植到 OCaml 时,您有两个基本选择:
-
将其视为包裹在额外的结构中。例如,您的
table.sig
可能会变得table_sig.ml
(而不是.mli
!(,并且签名将被称为Table_sig.TABLE
,而table.ml
将变得table_fn.ml
函子被称为Table_fn.IntMapTable
。有时您想稍微重新组织一下文件结构。例如,与其有两个模块
Table_sig
和Table_fn
,你可以选择只有一个同时包含签名和函子的Table
。OCaml倾向于使用命名约定,如调用签名S
和函子Make
,因此直观地将它们称为Table.S
和其他地方Table.Make
。 -
在某些情况下,您可以展平这个额外的包装器结构。特别:
一个。如果文件由单个结构声明组成,其 RHS 是
struct
表达式,则可以将其正文放在以声明的结构命名的 .ml 文件中。二.如果文件由单个签名声明组成,其 RHS 是
sig
表达式,并且根据大小写 (a( 仅使用一次来注释结构,则只需将其正文放在以相应结构命名的 .mli 文件中即可。
第二种往往是常见情况。