Я определил два типа модулей и два модуля
module type FOO = sig type e end
module type BAR = sig type t end
module Foo : FOO = struct type e = int end
module Bar : BAR = struct type t = int end
Затем я определяю функтор как
module Fun (F:FOO) (B:BAR with type t = F.e) = struct type x = string end
(это игрушечный пример, не обращайте внимания на тот факт, что F и B не используются функтором)
Теперь, если я определю модуль
module Bla = Fun (Foo) (Bar)
я получил
Error: Signature mismatch:
Modules do not match:
sig type t = Bar.t end
is not included in
sig type t = Foo.e end
Type declarations do not match:
type t = Bar.t
is not included in
type t = Foo.e
Хотя и Bar.t, и Foo.e определены как int, OCaml считает, что Bar.t и Foo.e разные. Именно так работает система набора текста, и имеет смысл рассматривать эти два типа в целом как разные (см. Последний абзац Функторы и абстракция типов).
Вопрос: Иногда мне может понадобиться пройти проверку типа, потому что для моих целей они могут считаться равными. Есть ли способ расслабиться?
Используя предложение Гаше об удалении принуждения, приведенный выше код можно записать как
module type FOO = sig type e end
module type BAR = sig type t end
module Foo = struct type e = int end
module Bar = struct type t = int end
module Fun (F : FOO with type e=int) (B : BAR with type t = int) = struct type x = F.e * B.t end
module Bla = Fun (Foo) (Bar)
который компилируется нормально. Как ни странно, я получаю
# let f x : Bla.x = (x,x);;
val f : Foo.e -> Bla.x = <fun>
Вопрос: почему он делает вывод, что x равно Foo.e? С тем же успехом это могло быть Bar.t?