使用“with type”时放松类型检查模块构建

发布于 2024-10-23 00:50:44 字数 1683 浏览 1 评论 0 原文

我定义了两个模块类型和两个模块

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

(这是一个玩具示例,请忽略函子不使用 FB 的事实)

现在,如果我定义模块

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.tFoo.e 都定义为 int OCaml 认为 Bar .tFoo.e 不同。这就是打字系统的工作方式,考虑到这两种类型总体上不同是有意义的(参见 函子和类型抽象)。

问题有时我可能希望它通过类型检查,因为就我的目的而言,它们可以被视为相等。有什么办法可以放松这个吗?


使用gasche关于消除强制的建议,上面的代码可以编写为

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>

问题:为什么它推断出xFoo.e?它也可能是 Bar.t

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

反差帅 2024-10-30 00:50:44

问题在于如何定义 FooBarmodule Foo : FOO = ...。通过在此处施加此签名,您可以“密封”模块并使类型抽象。它无法恢复。您应该在此处删除 : FOO 强制转换,并在稍后需要抽象时使用它。您还可以使用模块 Foo : (FOO with type e = int) = ...

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) = ....

漫雪独思 2024-10-30 00:50:44

我不确定打印机如何在相同类型中进行选择,但在这种情况下,您可以通过显式注释函数参数来使其打印不同的名称:

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

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文