Spec-Zone.ru › OCaml
☰Язык OCaml
  • Язык OCaml
  • Расширения языка

Глава 12. Расширения языка

2 Рекурсивные модули

(Добавлено в Objective Caml 3.07)

definition ::= ...
∣ module rec module-name : module-type = module-expr { and module-name : module-type = module-expr }
specification ::= ...
∣ module rec module-name : module-type { and module-name: module-type }

Рекурсивные определения модулей, вводимые конструкцией 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.

« Рекурсивные определения значенийАбстрактные типы »
Авторское право © 2026 Institut National de Recherche en Informatique et en Automatique

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/recursivemodules.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API