开发者

Relaxing type checking when using 'with type' construction in modules

I have defined two module types and two modules

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
开发者_运维百科

Then I define a functor as

module Fun (F:FOO) (B:BAR with type t = F.e) = struct type x = string end

(this is a toy example, please ignore the fact that F and B are not used by the functor)

Now, if I define the module

module Bla = Fun (Foo) (Bar)

I get

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

Although both Bar.t and Foo.e are defined as int OCaml considers Bar.t and Foo.e to be different. That's just the way the typing system works and it makes sense to consider these two types different in general (c.f. last paragraph of Functors and Type Abstraction).

Question: Sometimes I may want this to pass type checking because for my purposes they can be considered equal. Is there a way to relax this?


Using gasche's suggestion of removing coercion, the above code can be written as

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)

which compiles fine. Strangely, I get

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

Question: why does it infer that x is Foo.e? It could as well be Bar.t?


The problem is how you define Foo and Bar : module Foo : FOO = .... By imposing this signature here, you "seal" the module and make the type abstract. It cannot be reverted. You should remove the : FOO coercion here, and use it later when you need the abstraction. You could also use module Foo : (FOO with type e = int) = ....


I'm not sure how the printer chooses amongst equal types, but in this case you can cause it to print a different name by explicitly annotating your function argument:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜