Расслабляющая проверка типов при использовании конструкции с типом в модулях - PullRequest
2 голосов
/ 17 марта 2011

Я определил два типа модулей и два модуля

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?

Ответы [ 2 ]

5 голосов
/ 17 марта 2011

Проблема в том, как вы определяете Foo и Bar: module Foo : FOO = .... Установив здесь эту подпись, вы «запечатываете» модуль и делаете тип абстрактным. Это не может быть отменено. Вы должны удалить здесь : FOO принуждение и использовать его позже, когда вам понадобится абстракция. Вы также можете использовать module Foo : (FOO with type e = int) = ....

0 голосов
/ 18 марта 2011

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

# let f (x:Bar.t) : Bla.x = (x,x);;
val f : Bar.t -> Bla.x = <fun>
...