Spec-Zone.ru › OCaml 4.14

10.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 10.2).
  Module M defines an unsafe value, x .
  Module N defines an unsafe value, x .

Обратите внимание, что в случае спецификации типы модулей должны быть заключены в скобки, если они используют конструкцию with ограничения модуля.

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

Spec-Zone.ru

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