强制转换类型的缩写记录

3
为什么无法在OCaml中强制转换记录类型?像 int 这样的基本类型可以正常工作。
下面是一个示例,我构建了一个名为 M 的基本模块,并将其包含在模块 A 中。在 A 模块中,M.t 被缩写为类型。只要 M.tint,我就可以执行 A.t' :> M.t。当我将其更改为 {i : int} 时,编译器会报告它不是子类型。我猜这里有一个非常具体的原因?
module M = struct
  type t = {i : int}
  let make () = {i = 10}
end

module A : sig
  include module type of M
  type t' = private t
  val make : unit -> t'
end = struct
  include M
  type t' = t
end

在顶层:

(A.make() :> M.t);;
Error: Type A.t' is not a subtype of M.t 
1个回答

3
这是因为A.t'M.t没有关系,因为include不会“保留”相等性,它只是在原地复制模块结构(或签名),并将其作为新的类型和值内联。因此,类型M.tA.t以及A.t'没有任何关系(而不同的记录类型不像对象或模块那样定义了结构子类型)。明显的解决方法是type t' = private M.t更新: 似乎上述内容并不完全正确,因为签名中的type t' = private M.t和实现中的include M type t' = t都能通过类型检查,所以include M保存了相等性(否则它就无法与签名type t' = private M.t匹配),不像是将M的内容复制粘贴到include M的位置。但这在include module type of中却不成立,因为它会创建新的类型…

3
另一个修复方法是在包含模块类型时明确声明你希望类型相等:include module type of M with type t = M.t。翻译完毕。 - hcarty
你知道为什么对于记录类型这是必须的,但是对于像 int 这样的基本类型却不需要吗?如果你把 t 改成 type t = int,上述代码就会起作用。 - Olle Härstedt
1
因为在 type t = inttype t' = int 中,tt' 是现有类型的别名(类型缩写),可以互换使用。但是,在 type t = {x : int}type t' = {x:int} 中,这些是两种新类型,没有任何关系。 - ygrek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接