标准 ML 实现文件中的定义是外部可见的(但不在签名文件中)

Definition in Standard ML implementation file is externally visible (but not in the signature file)

我正在将 SML 起始代码从 Tiger book 转换为 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 时,您有两个基本选择:

  1. 将其视为包裹在一个额外的结构中。例如,您的 table.sig 可能会变成 table_sig.ml(而不是 .mli!)并且签名会被称为 Table_sig.TABLE,而 table.ml 会变成 table_fn.ml 函子被称为 Table_fn.IntMapTable.

    有时您想稍微重新组织一下文件结构。例如,您可以选择只有一个 Table 包含签名和仿函数,而不是有两个模块 Table_sigTable_fn。 OCaml 然后倾向于使用命名约定,例如调用签名 S 和仿函数 Make,因此在其他地方直观地将它们称为 Table.STable.Make

  2. 在某些情况下,您可以展平这个额外的包装器结构。特别是:

    一个。如果文件包含一个结构声明,其 RHS 是一个 struct 表达式,那么您可以将其主体放在一个以声明的结构命名的 .ml 文件中。

    b。如果该文件包含一个签名声明,其 RHS 是一个 sig 表达式,并且只使用一次来按照案例 (a) 注释一个结构,那么您可以将其主体放在一个名为的 .mli 文件中对应结构后

第二种情况比较常见。