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

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

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

(Введены в Objective Caml 3.07)

определение ::= ...
∣ module rec имя_модуля : тип_модуля = выражение_модуля { and имя_модуля : тип_модуля = выражение_модуля }
описание ::= ...
∣ module rec имя_модуля : тип_модуля { and имя_модуля: тип_модуля }

Определения рекурсивных модулей, введенные конструкцией module rec …and …, обобщают обычные определения модулей module имя_модуля = выражение_модуля и описания модулей module имя_модуля : тип_модуля, позволяя определению выражения_модуля и типу_модуля рекурсивно ссылаться на идентификаторы модулей, которые определяются.

Типичный пример рекурсивного определения модуля:

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: класс рекурсивных определений, принимаемых компилятором, а также его динамическая семантика не являются окончательными и могут быть изменены в будущих версиях.

В настоящее время компилятор требует, чтобы все циклы зависимостей между рекурсивно определёнными идентификаторами модулей проходили через по крайней мере один «безопасный» модуль. Модуль является «безопасным», если все определения значений, которые он содержит, имеют типы функций тип_выражения1 -> тип_выражения2. Вычисление рекурсивного определения модуля происходит путём создания начальных значений для участвующих безопасных модулей, связывая все (функциональные) значения с 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 .

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

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

© 1995-2024 INRIA.
https://ocaml.org/manual/5.2/recursivemodules.html

Spec-Zone.ru

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