第 12 章 語言擴展
2 遞迴模組
(在 Objective Caml 3.07 中引入)
遞迴模組定義,由 module rec …and … 建構引入,推廣了正規模組定義 module module-name = module-expr 和模組規格 module module-name : module-type,允許定義 module-expr 和 module-type 遞迴地參考正在定義的模組識別符。遞迴模組定義的一個典型例子是
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 的一個實驗性擴展:接受的遞迴定義類別以及其動態語義並非最終,並且可能會在未來的版本中更改。
目前,編譯器要求遞迴定義的模組識別符之間的所有依賴循環必須至少通過一個「安全」模組。「安全」模組是指它包含的所有值定義都具有函數類型 typexpr1 -> typexpr2。遞迴模組定義的評估過程是,先為涉及的安全模組建立初始值,將所有 (函數) 值綁定到 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
Error: 無法安全地評估以下遞迴定義模組循環的定義:M -> N -> M。此循環中沒有安全模組 (請參閱手冊第 12.2 節)。模組 M 定義了一個不安全的值 x 。模組 N 定義了一個不安全的值 x 。
請注意,在 specification 的情況下,如果 module-type 使用 with mod-constraint 建構,則必須加上括號。
版權所有 © 2024 Institut National de Recherche en Informatique et en Automatique