Глава 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
Exception:
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: Cannot safely evaluate the definition of the following cycle
of recursively-defined modules: M -> N -> M.
There are no safe modules in this cycle (see manual section 12.2).
Module M defines an unsafe value, x .
Module N defines an unsafe value, x . Обратите внимание: в случае specification типы module-type необходимо заключать в скобки, если в них используется конструкция with mod-constraint.
© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/recursivemodules.html