module StringOrdering : ORDERING
является декларацией модуля.Вы можете использовать это в подписи, чтобы сказать, что подпись содержит поле модуля с именем StringOrdering
и подписью ORDERING
.Это не имеет смысла в модуле.
Вам нужно определить модуль где-нибудь, который реализует необходимые вам операции.Определение модуля может выглядеть примерно так:
module StringOrderingImplementation = struct
type t = string
let isLess x y = x <= y
end
Если вы хотите скрыть определение типа t
, вам нужно создать другой модуль, в котором определение будет абстрактным.Операция по созданию нового модуля из старого называется герметизацией и выражается через оператор :
.
module StringOrderingAbstract = (StringOrdering : ORDERING)
Тогда StringOrderingImplementation.isLess "a" "b"
хорошо напечатан, тогда как StringOrderingAbstract.isLess "a" "b"
не может бытьтипизируется, поскольку StringOrderingAbstract.t
является абстрактным типом, который не совместим с string
или любым другим существующим типом.На самом деле невозможно создать значение типа StringOrderingAbstract.t
, поскольку модуль не содержит конструктора.
Если у вас есть модуль компиляции foo.ml
, это модуль Foo
, аподпись этого модуля задается интерфейсным файлом foo.mli
.То есть файлы foo.ml
и foo.mli
эквивалентны определению модуля
module Foo = (struct (*…contents of foo.ml…*) end :
sig (*…contents of foo.mli…*) end)
При компиляции модуля, использующего Foo
, компилятор смотрит только на foo.mli
(или, скорее, на результатего компиляции: foo.cmi
), а не foo.ml
¹.Вот как интерфейсы и отдельная компиляция сочетаются друг с другом.C нуждается #include <foo.h>
, потому что ему не хватает пространства имен;в OCaml Foo.bar
автоматически ссылается на bar
, определенный в модуле компиляции foo
, если в области нет другого модуля с именем Foo
.
¹ На самом деле, компилятор собственного кодасмотрит на реализацию Foo
для выполнения оптимизации (встраивание).Тип проверки никогда не смотрит ни на что, кроме того, что в интерфейсе.