Why can't I coerce record types in OCaml? Base types like int works fine.

Below is an example where I construct a base module M which I include in module A. M.t is type abbriviated in A. As long as M.t is int, I can do A.t' :> M.t. When I change it to {i : int}, the compiler says it's not a subtype. I'm guessing there is a very specific reason for this?

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

In the toplevel:

(A.make() :> M.t);;
Error: Type A.t' is not a subtype of M.t 
有帮助吗?

解决方案

That's because A.t' has no relation to M.t, because include does not "preserve" equality, it just literally duplicates the module structure (or signature) and inlines it in place (as fresh types and values). So type M.t doesn't have any relation to A.t and therefore to A.t' (and different record types do not have structural subtyping defined like say objects or modules). Obvious fix is type t' = private M.t.

UPDATE

It appears the above is not fully correct, because type t' = private M.t in signature and include M type t' = t in implemention do typecheck, so include M preserves the equality (otherwise it couldn't match the signature type t' = private M.t), unlike copypasting the contents of M in the place of include M. But this "obviously" doesn't hold for include module type of which creates fresh types..

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top