Я определил два типа модулей и два модуля
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
?