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