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

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

5 Модули первого класса

(Введены в OCaml 3.12; синтаксис шаблонов и вывод типов пакетов введены в 4.00; структурное сравнение типов пакетов введено в 4.02.; уменьшенное количество скобок с 4.05)

typexpr ::= ...
∣ (module package-type)
module-expr ::= ...
∣ (val expr [: package-type])
expr ::= ...
∣ (module module-expr [: package-type])
pattern ::= ...
∣ (module module-name [: package-type])
package-type ::= modtype-path
∣ modtype-path with package-constraint { and package-constraint }
package-constraint ::= type typeconstr = typexpr

Модули обычно рассматриваются как статические компоненты. Это расширение позволяет упаковать модуль в качестве значения первого класса, которое позже может быть динамически распаковано в модуль.

Выражение ( module module-expr : package-type ) преобразует модуль (структуру или функтор), обозначенный выражением модуля module-expr, в значение ядра языка, которое инкапсулирует этот модуль. Тип этого значения ядра языка — ( module package-type ). Аннотация package-type может быть опущена, если её можно вывести из контекста.

Обратно, выражение модуля ( val expr : package-type ) оценивает выражение ядра языка expr до значения, которое должно иметь тип module package-type, и извлекает модуль, который был инкапсулирован в этом значении. Опять же, package-type может быть опущено, если тип expr известен. Если выражение модуля уже заключено в скобки, например, аргументы функторов, дополнительные скобки не нужны: Map.Make(val key).

Шаблон ( module module-name : package-type ) сопоставляет пакет с типом package-type и связывает его с module-name. Он не разрешён в связываниях let на верхнем уровне.

Класс синтаксических конструкций package-type, встречающийся в выражении типа ( module package-type ) и в аннотированных формах, представляет собой подмножество типов модулей. Это подмножество состоит из именованных типов модулей с необязательными ограничениями ограниченной формы: можно указать только непараметризованные типы.

Для целей проверки типов (и начиная с OCaml 4.02) типы пакетов сравниваются с использованием структурного сравнения типов модулей.

В общем случае, выражение модуля ( val expr : package-type ) не может быть использовано в теле функтора, так как это может привести к некорректности в сочетании с прикладными функторами. С OCaml 4.02 это ослаблено в двух аспектах: если package-type не содержит именованных объявлений типов (типы, созданные с соответствующей идентичностью), то это выражение может использоваться в любом месте, а если оно содержит такие типы, то оно может использоваться в теле порождающего функтора, описанного в разделе ‍12.15. Оно также может использоваться в любом контексте локального связывания модулей let module module-name = ( val expr1 : package-type ) in expr2.

Базовый пример

Типичное использование модулей первого класса — это выбор в момент выполнения среди нескольких реализаций сигнатуры. Каждая реализация — это структура, которую можно инкапсулировать как модуль первого класса, а затем хранить в структуре данных, такой как хеш-таблица:

type picture = …
module type DEVICE = sig
  val draw : picture -> unit
  …
end
let devices : (string, (module DEVICE)) Hashtbl.t = Hashtbl.create 17

module SVG = struct … end
let _ = Hashtbl.add devices "SVG" (module SVG : DEVICE)

module PDF = struct … end
let _ = Hashtbl.add devices "PDF" (module PDF : DEVICE)

Затем можно выбрать одну реализацию на основе аргументов командной строки, например:

let parse_cmdline () = …
module Device =
  (val (let device_name = parse_cmdline () in
        try Hashtbl.find devices device_name
        with Not_found ->
          Printf.eprintf "Unknown device %s\n" device_name;
          exit 2)
   : DEVICE)

Или выбор можно выполнить внутри функции:

let draw_using_device device_name picture =
  let module Device =
    (val (Hashtbl.find devices device_name) : DEVICE)
  in
  Device.draw picture
Расширенные примеры

С модулями первого класса можно параметризовать код относительно реализации модуля без использования функтора.

let sort (type s) (module Set : Set.S with type elt = s) l =
  Set.elements (List.fold_right Set.add l Set.empty)

val sort : (module Set.S with type elt = 's) -> 's list -> 's list = 

Для использования этой функции можно обернуть функтор Set.Make:

let make_set (type s) cmp =
  let module S = Set.Make(struct
    type t = s
    let compare = cmp
  end) in
  (module S : Set.S with type elt = s)

val make_set : ('s -> 's -> int) -> (module Set.S with type elt = 's) = 
« Локально абстрактные типыВосстановление типа модуля »
Авторские права © 2024 Institut National de Recherche en Informatique et en Automatique

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

Spec-Zone.ru

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