第 12 章 语言扩展
2 递归模块
(在 Objective Caml 3.07 中引入)
递归模块定义,由 module rec …and … 结构引入,概括了常规模块定义 module 模块名 = 模块表达式 和模块规范 module 模块名 : 模块类型,允许定义的 模块表达式 和 模块类型 递归地引用正在定义的模块标识符。递归模块定义的一个典型示例是
module rec A : sig type t = Leaf of string | Node of ASet.t val compare: t -> t -> int end = struct type t = Leaf of string | Node of ASet.t let compare t1 t2 = match (t1, t2) with | (Leaf s1, Leaf s2) -> Stdlib.compare s1 s2 | (Leaf _, Node _) -> 1 | (Node _, Leaf _) -> -1 | (Node n1, Node n2) -> ASet.compare n1 n2 end and ASet : Set.S with type elt = A.t = Set.Make(A)
它可以给出以下规范
module rec A : sig type t = Leaf of string | Node of ASet.t val compare: t -> t -> int end and ASet : Set.S with type elt = A.t
这是一个 OCaml 的实验性扩展:接受的递归定义类别及其动态语义不是最终的,并且可能会在将来的版本中发生变化。
目前,编译器要求递归定义的模块标识符之间所有依赖循环都必须至少通过一个“安全”模块。如果它包含的所有值定义都具有函数类型 类型表达式1 -> 类型表达式2,则该模块为“安全”。递归模块定义的求值通过为涉及的安全模块构建初始值来进行,将所有(函数)值绑定到 fun _ -> raise Undefined_recursive_module。然后求值定义模块表达式,并将安全模块的初始值替换为由此计算出的值。如果在此计算过程中应用了安全模块的函数组件(这对应于一个不合理的递归定义),则在运行时引发 Undefined_recursive_module 异常
module rec M: sig val f: unit -> int end = struct let f () = N.x end and N:sig val x: int end = struct let x = M.f () end
异常:Undefined_recursive_module ("extensions/recursivemodules.etex", 1, 43)。
如果依赖循环中没有安全模块,则会引发错误
module rec M: sig val x: int end = struct let x = N.y end and N:sig val x: int val y:int end = struct let x = M.x let y = 0 end
错误:无法安全地评估以下递归定义的模块循环的定义:M -> N -> M。此循环中没有安全模块(请参阅手册第 12.2 节)。模块 M 定义了一个不安全的值,x。模块 N 定义了一个不安全的值,x。
请注意,在 规范 情况下,如果 模块类型 使用 with 模块约束 结构,则必须将其括在括号中。
版权所有 © 2024 法国国家信息与自动化研究所