10.8 Типовые псевдонимы модулей
(Введено в OCaml 4.02)
|
Вышеприведенное описание внутри сигнатуры соответствует только определению модуля, равному module-path. И наоборот, типовой псевдоним модуля может совпадать с самим собой или с любым типом-супертипом типа модуля, на который он ссылается.
Существуют определенные ограничения на module-path:
- он должен иметь вид M0.M1...Mn (т.е. без применений функторов);
- внутри тела функтора M0 не должен быть одним из параметров функтора;
- внутри рекурсивного определения модуля M0 не должен быть одним из рекурсивно определенных модулей.
Такие спецификации также выводятся. А именно, когда P — путь, удовлетворяющий приведенным выше ограничениям,
module N = P
имеет тип
module N = P
Типовые псевдонимы модулей используются при проверке равенства путей модулей. То есть, в контексте, где имя модуля N известно как псевдоним для P, не только эти два пути модулей считаются равными, но также F(N) и F(P) распознаются как равные. В режиме компиляции по умолчанию это единственное отличие от предыдущего подхода к псевдонимам модулей, у которых просто тот же тип модуля, что и у модуля, на который они ссылаются.
Когда включён флаг компилятора -no-alias-deps, типовые псевдонимы модулей также используются для избежания введения зависимостей между единицами компиляции. А именно, псевдоним модуля, ссылающийся на модуль внутри другой единицы компиляции, не создаёт зависимость при компоновке, пока он не дереференцируется; он всё же вводит зависимость при компиляции, если нужно прочитать интерфейс, т.е. если модуль является подмодулем единицы компиляции или если ссылаются на какие-либо составляющие типа. Кроме того, обращение к псевдониму модуля создаёт зависимость при компоновке от единицы компиляции, содержащей модуль, на который ссылается псевдоним, а не от единицы компиляции, содержащей сам псевдоним. Обратите внимание, что эти различия в поведении при компоновке могут быть несовместимы с предыдущим поведением, так как некоторые единицы компиляции могут не извлекаться из библиотек, и их побочные эффекты игнорируются.
Эти ослабленные зависимости позволяют использовать псевдонимы модулей вместо механизма -pack. Предположим, у вас есть библиотека Mylib, состоящая из модулей A и B. Используя -pack, нужно было бы выполнить команду
ocamlc -pack a.cmo b.cmo -o mylib.cmo
в результате чего получилась бы единица компиляции Mylib, физически содержащая A и B в качестве подмодулей и без зависимостей от соответствующих единиц компиляции. Вот конкретный пример альтернативного подхода:
- Переименовать файлы, содержащие A и B, в Mylib__A и Mylib__B.
- Создать интерфейс для упаковки Mylib.ml, содержащий следующие строки.
module A = Mylib__A module B = Mylib__B
- Скомпилировать Mylib.ml с помощью -no-alias-deps, а другие файлы — с помощью -no-alias-deps и -open Mylib (последнее эквивалентно добавлению строки open! Mylib в начало каждого файла).
ocamlc -c -no-alias-deps Mylib.ml ocamlc -c -no-alias-deps -open Mylib Mylib__*.mli Mylib__*.ml
- Наконец, создайте библиотеку, содержащую все единицы компиляции, и экспортируйте все скомпилированные интерфейсы.
ocamlc -a Mylib*.cmo -o Mylib.cma
Этот подход позволяет напрямую получать доступ к A и B внутри библиотеки и как Mylib.A и Mylib.B снаружи. У него также есть преимущество, что Mylib больше не монолитна: если вы используете Mylib.A, будет подключена только Mylib__A, а не Mylib__B.
Обратите внимание на использование двойных подчеркиваний в Mylib__A и Mylib__B. Это было сделано намеренно; компилятор использует следующий эвристический подход при печати путей: дан путь Lib__fooBar, если Lib.FooBar существует и является псевдонимом для Lib__fooBar, то компилятор всегда будет отображать Lib.FooBar, а не Lib__fooBar. Таким образом, длинные имена Mylib__ остаются скрытыми, а все, что видит пользователь, — это более удобные имена с точкой. Именно так компилируется стандартная библиотека OCaml.
© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/modulealias.html