Spec-Zone.ru › OCaml 4.14

9.11 Модульные выражения (реализации модулей)

  • 9.11.1 Простые модульные выражения
  • 9.11.2 Структуры
  • 9.11.3 Функторы

Модульные выражения являются модульным эквивалентом выражений значений: они вычисляются в модули, предоставляя, таким образом, реализации для спецификаций, выраженных в типах модулей.

module-expr ::= module-path
∣ struct [ module-items ] end
∣ functor ( module-name : module-type ) -> module-expr
∣ module-expr ( module-expr )
∣ ( module-expr )
∣ ( module-expr : module-type )
module-items ::= { ;; } ( definition ∣ expr ) { { ;; } ( definition ∣ ;; expr) } { ;; }
definition ::= let [rec] let-binding { and let-binding }
∣ external value-name : typexpr = external-declaration
∣ type-definition
∣ exception-definition
∣ class-definition
∣ classtype-definition
∣ module module-name { ( module-name : module-type ) } [ : module-type ] = module-expr
∣ module type modtype-name = module-type
∣ open module-path
∣ include module-expr

См. также следующие расширения языка: рекурсивные модули, модули первого класса, переопределение в операторах open, атрибуты, узлы расширения и генеративные функторы.

9.11.1 Простые модульные выражения

Выражение module-path вычисляется в модуль, связанный с именем module-path.

Выражение ( module-expr ) вычисляется в тот же модуль, что и module-expr.

Выражение ( module-expr : module-type ) проверяет, что тип module-expr является подтипом module-type, то есть, что все компоненты, указанные в module-type, реализованы в module-expr, и их реализация соответствует требованиям, указанным в module-type. Другими словами, он проверяет, что реализация module-expr соответствует спецификации типа module-type. Весь выражение вычисляется в тот же модуль, что и module-expr, за исключением того, что все компоненты, не указанные в module-type, скрыты и больше недоступны.

9.11.2 Структуры

Структуры struct … end представляют собой коллекции определений для имён значений, имён типов, исключений, имён модулей и имён типов модулей. Определения вычисляются в порядке их появления в структуре. Области связей, выполняемых определениями, распространяются до конца структуры. Вследствие этого определение может ссылаться на имена, связанные предыдущими определениями в той же структуре.

Для совместимости с фразами верхнего уровня (глава 12), необязательные ;; допускаются после и перед каждым определением в структуре. Эти ;; не имеют семантического значения. Аналогично, expr, предваряемый ;;, допускается как компонент структуры. Это эквивалентно let _ = expr, т. е. expr вычисляется для своих побочных эффектов, но не связывается ни с каким идентификатором. Если expr является первым компонентом структуры, предшествующий ;; можно опустить.

Определения значений

Определение значения let [rec] let-binding { and let-binding } связывает имена значений так же, как и выражение let … in … (см. раздел 9.7.2). Имена значений, появляющиеся в левых частях связываний, связываются с соответствующими значениями в правых частях.

Определение значения external value-name : typexpr = external-declaration реализует value-name как внешнюю функцию, указанную в external-declaration (см. главу 20).

Определения типов

Определение одного или нескольких компонентов типа записывается как type typedef { and typedef } и состоит из последовательности взаимно рекурсивных определений имён типов.

Определения исключений

Исключения определяются с помощью синтаксиса exception constr-decl или exception constr-name = constr.

Определения классов

Определение одного или нескольких классов записывается как class class-binding { and class-binding } и состоит из последовательности взаимно рекурсивных определений имён классов. Более точное описание определений классов приведено в разделе 9.9.3.

Определения типов классов

Определение одного или нескольких классов записывается как class type classtype-def { and classtype-def } и состоит из последовательности взаимно рекурсивных определений имён типов классов. Более подробное описание определений типов классов приведено в разделе 9.9.5.

Определения модулей

Основная форма определения компонента модуля — module module-name = module-expr, которая вычисляет module-expr и связывает результат с именем module-name.

Можно записать

module module-name : module-type = module-expr

вместо

module module-name = ( module-expr : module-type ).

Ещё одна производная форма —

module module-name ( name1 : module-type1 ) … ( namen : module-typen ) = module-expr

что эквивалентно

module module-name = functor ( name1 : module-type1 ) -> … -> module-expr

Определения типов модулей

Определение типа модуля записывается как module type modtype-name = module-type. Оно связывает имя modtype-name с типом модуля, обозначаемым выражением module-type.

Открытие пути модуля

Выражение open module-path в структуре не определяет никаких компонентов и не выполняет никаких связываний. Оно просто влияет на обработку следующих элементов структуры, позволяя обращаться к компонентам модуля, обозначаемого module-path, по их простым именам name вместо доступа по пути module-path . name. Область действия open заканчивается в конце выражения структуры.

Включение компонентов другой структуры

Выражение include module-expr в структуре повторно экспортирует все определения структуры, обозначаемой module-expr, в текущую структуру. Например, если вы определите модуль S следующим образом

module S = struct type t = int  let x = 2 end

определение модуля B как

module B = struct include S  let y = (x + 1 : t) end

эквивалентно его определению как

module B = struct type t = S.t  let x = S.x  let y = (x + 1 : t) end

Разница между open и include заключается в том, что open просто предоставляет короткие имена для компонентов открытой структуры, не определяя никаких компонентов текущей структуры, а include также добавляет определения для компонентов включённой структуры.

9.11.3 Функторы

Определение функтора

Выражение functor ( module-name : module-type ) -> module-expr вычисляет функтор, принимающий в качестве аргумента модули типа module-type1, связывает module-name с этими модулями, вычисляет module-expr в расширенной среде и возвращает получившиеся модули в качестве результатов. Ограничений на тип аргумента функтора не накладывается; в частности, функтор может принимать в качестве аргумента другой функтор («функтор высшего порядка»).

Когда результат выражения модуля сам является функтором,

функтор ( имя1 : тип-модуля1 ) -> … -> функтор ( имяn : тип-модуляn ) -> выражение-модуля

можно использовать сокращённую форму

функтор ( имя1 : тип-модуля1 ) … ( имяn : тип-модуляn ) -> выражение-модуля

Применение функтора

Выражение выражение-модуля1 ( выражение-модуля2 ) вычисляет выражение-модуля1 в функтор и выражение-модуля2 в модуль, и применяет первый ко второму. Тип выражение-модуля2 должен соответствовать типу, ожидаемому для аргументов функтора выражение-модуля1.

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/modules.html

Spec-Zone.ru

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