Упрощенная проверка типов при использовании конструкции with type в модулях

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

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?


person Surikator    schedule 17.03.2011    source источник


Ответы (2)


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

person gasche    schedule 17.03.2011
comment
Хорошо, достаточно честно. Я оставлю принуждение на как можно более поздний срок. В этом есть что-то нехорошее, но код, который у меня есть (приведенный выше является игрушечным примером), теперь работает, так что я буду жить с этим. Спасибо! - person Surikator; 17.03.2011

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

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