Spec-Zone.ru › OCaml 5.0

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.

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/recursivemodules.html

Spec-Zone.ru

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