Глава 11 Язык программирования OCaml
10 Типы модулей (описания модулей)
Типы модулей являются модульными аналогами выражений типов: они определяют общий вид и свойства типов модулей.
|
|
См. также следующие расширения языка: восстановление типа модуля, подстановка внутри подписи, алиасы модулей на уровне типов, атрибуты, узлы расширений, порождающие функторы и подстановки типов модулей.
10.1 Простые типы модулей
Выражение путь-к-типу-модуля эквивалентно типу модуля, связанному с именем путь-к-типу-модуля. Выражение ( тип-модуля ) обозначает тот же тип, что и тип-модуля.
10.2 Подписи
Подписи являются спецификациями типов для структур. Подписи sig … end представляют собой коллекции спецификаций типов для имен значений, имён типов, исключений, имён модулей и имён типов модулей. Структура будет соответствовать подписи, если структура предоставляет определения (реализации) для всех имён, указанных в подписи (и, возможно, больше), и эти определения соответствуют требованиям типов, заданным в подписи.
После каждой спецификации в подписи разрешено необязательное ;;. Оно служит синтаксическим разделителем без семантического значения.
Спецификации значений
Спецификация компонента значения в подписи записывается как val имя-значения : выражение-типа, где имя-значения — имя значения, а выражение-типа — его ожидаемый тип.
Форма external имя-значения : выражение-типа = объявление-внешнего-функции аналогична, за исключением дополнительного требования о реализации в виде внешней функции, указанной в объявление-внешнего-функции (см. главу 22).
Спецификации типов
Определение одного или нескольких компонентов типа в сигнатуре записывается как 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-2024 INRIA.
https://ocaml.org/manual/5.2/modtypes.html