Глава 12 Расширения языка
2 Рекурсивные модули
(Введены в Objective Caml 3.07)
|
Определения рекурсивных модулей, введенные конструкцией 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 ограничение_модуля.
© 1995-2024 INRIA.
https://ocaml.org/manual/5.2/recursivemodules.html