Глава 11 Язык OCaml
10 Типы модулей (спецификации модулей)
Типы модулей — эквивалент выражений типов на уровне модулей: они задают общую форму и свойства типов модулей.
|
|
См. также следующие расширения языка: получение типа модуля, подстановка в сигнатуре, псевдонимы модулей на уровне типов, атрибуты, узлы расширений, генеративные функторы и подстановки типов модулей.
10.1 Простые типы модулей
Выражение modtype-path эквивалентно типу модуля, связанному с именем modtype-path. Выражение ( module-type ) обозначает тот же тип, что и module-type.
10.2 Сигнатуры
Сигнатуры задают типы структур. Сигнатуры sig … end представляют собой наборы спецификаций типов для имён значений, имён типов, исключений, имён модулей и имён типов модулей. Структура соответствует сигнатуре, если она предоставляет определения (реализации) всех имён, указанных в сигнатуре (и, возможно, других имён), и эти определения удовлетворяют требованиям к типам, заданным в сигнатуре.
После каждой спецификации в сигнатуре допускается необязательный элемент ;;. Он служит синтаксическим разделителем и не имеет семантического значения.
Спецификации значений
Спецификация компонента-значения в сигнатуре записывается как val value-name : typexpr, где value-name — имя значения, а typexpr — его ожидаемый тип.
Форма external value-name : typexpr = external-declaration аналогична, но дополнительно требует, чтобы имя было реализовано как внешняя функция, указанная в external-declaration (см. главу 23).
Спецификации типов
Спецификация одного или нескольких компонентов-типов в сигнатуре записывается как type typedef { and typedef } и состоит из последовательности взаимно рекурсивных определений имён типов.
Каждое определение типа в сигнатуре задаёт необязательное уравнение типа = typexpr и необязательное представление типа = constr-decl … или = { field-decl … }. Реализация имени типа в соответствующей структуре должна быть совместима с выражением типа, заданным в уравнении (если оно указано), и иметь заданное представление (если оно указано). В свою очередь, пользователи этой сигнатуры могут полагаться на уравнение или представление типа, если они указаны. Точнее, возможны следующие четыре случая:
- Абстрактный тип: без уравнения и без представления.
-
Имена, определённые в сигнатуре как абстрактные типы, в соответствующей структуре можно реализовать любым видом определения типа (при условии, что число параметров типа совпадает). Точная реализация типа будет скрыта от пользователей структуры. В частности, если тип реализован как вариантный тип или тип-запись, соответствующие конструкторы и поля будут недоступны пользователям; если тип реализован как синоним, равенство типов между именем типа и правой частью синонима будет скрыто от пользователей структуры. Пользователи структуры считают такой тип несовместимым с любым другим типом: создан новый тип. - Синоним типа: уравнение = typexpr, без представления.
-
Имя типа должно быть реализовано типом, совместимым с typexpr. Все пользователи структуры знают, что имя типа совместимо с typexpr. - Новый вариантный тип или тип-запись: без уравнения, с представлением.
-
Имя типа должно быть реализовано вариантным типом или типом-записью, содержащими в точности указанные конструкторы или поля. Все пользователи структуры имеют доступ к конструкторам или полям и могут использовать их для создания значений этого типа или проверки таких значений. Однако пользователи структуры считают такой тип несовместимым с любым другим типом: создан новый тип. - Повторно экспортируемый вариантный тип или тип-запись: с уравнением и представлением.
-
Этот случай объединяет два предыдущих: представление типа становится видимым всем пользователям, и новый тип не создаётся.
Спецификация исключения
Спецификация exception constr-decl в сигнатуре требует, чтобы соответствующая структура предоставляла исключение с именем и аргументами, указанными в определении, и делает это исключение доступным всем пользователям структуры.
Спецификации классов
Спецификация одного или нескольких классов в сигнатуре записывается как class class-spec { and class-spec } и состоит из последовательности взаимно рекурсивных определений имён классов.
Более подробное описание спецификаций классов приведено в разделе 11.9.4.
Спецификации типов классов
Спецификация одного или нескольких типов классов в сигнатуре записывается как class type classtype-def { and classtype-def } и состоит из последовательности взаимно рекурсивных определений имён типов классов. Более подробное описание спецификаций типов классов приведено в разделе 11.9.5.
Спецификации модулей
Спецификация компонента-модуля в сигнатуре записывается как module module-name : module-type, где module-name — имя компонента-модуля, а module-type — его ожидаемый тип. Модули могут быть вложены на любую глубину; в частности, функторы могут входить в состав структур, а типы функторов — в состав сигнатур.
Чтобы задать компонент-модуль, являющийся функтором, можно написать
вместо
Спецификации типов модулей
Компонент типа модуля в сигнатуре можно задать как манифестный или абстрактный тип модуля.
Спецификация абстрактного типа модуля module type modtype-name позволяет реализовать имя modtype-name любым типом модуля в соответствующей сигнатуре, но скрывает реализацию типа модуля от всех пользователей сигнатуры.
Спецификация манифестного типа модуля module type modtype-name = module-type требует, чтобы имя modtype-name было реализовано типом модуля module-type в соответствующей сигнатуре, но делает равенство между modtype-name и module-type очевидным для всех пользователей сигнатуры.
Открытие пути к модулю
Выражение open module-path в сигнатуре не задаёт никаких компонентов. Оно лишь влияет на разбор следующих элементов сигнатуры, позволяя ссылаться на компоненты модуля, обозначенного module-path, по их простым именам name, а не через обращение по пути module-path . name. Действие open заканчивается в конце выражения сигнатуры.
Включение сигнатуры
Выражение include module-type в сигнатуре выполняет текстовое включение компонентов сигнатуры, обозначенной module-type. Оно действует так, как если бы компоненты включённой сигнатуры были скопированы в место расположения include. Аргумент module-type должен ссылаться на тип модуля, являющийся сигнатурой, а не типом функтора.
10.3 Типы функторов
Выражение типа модуля [functor] ( module-name : module-type1 ) -> module-type2 — это тип функторов (функций из модулей в модули), которые принимают в качестве аргумента модуль типа module-type1 и возвращают модуль типа module-type2. Тип модуля module-type2 может использовать имя module-name для обращения к компонентам-типам фактического аргумента функтора. Если тип module-type2 не зависит от компонентов-типов module-name, выражение типа модуля можно записать в сокращённой форме module-type1 -> module-type2 . Ограничений на тип аргумента функтора нет; в частности, функтор может принимать в качестве аргумента другой функтор (функтор «высшего порядка»).
Если результирующий тип модуля сам является типом функтора,
можно использовать сокращённую форму
10.4 Оператор with
Предположим, что module-type обозначает сигнатуру. Выражение module-type with mod-constraint { and mod-constraint } обозначает ту же сигнатуру, к спецификациям некоторых типов которой добавлены уравнения, как описано ограничениями, следующими за ключевым словом with. Ограничение type [type-parameters] typeconstr = typexpr добавляет уравнение типа = typexpr к спецификации компонента-типа с именем typeconstr в ограничиваемой сигнатуре. Ограничение module module-path = extended-module-path добавляет уравнения типов ко всем компонентам-типам подструктуры, обозначенной module-path, делая их эквивалентными соответствующим компонентам-типам структуры, обозначенной extended-module-path.
Например, если имя типа модуля S связано с сигнатурой
sig type t module M: (sig type u end) end
то S with type t=int обозначает сигнатуру
sig type t=int module M: (sig type u end) end
а S with module M = N обозначает сигнатуру
sig type t module M: (sig type u=N.u end) end
Функтор, принимающий два аргумента типа S, у которых общий компонент t, записывается так:
functor (A: S) (B: S with type t = A.t) ...
Ограничения добавляются слева направо. После применения каждого ограничения полученная сигнатура должна быть подтипом сигнатуры, существовавшей до применения этого ограничения. Таким образом, оператор with может только добавлять информацию о компонентах-типах сигнатуры, но никогда не удалять её.
© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/modtypes.html