Let me first explain what is wrong with your code.
The message type in `Cmdlface` is defined as an abstract type with only one operation `cmd : message -> unit`. The module `Cmd` provides a possible implementation for this abstract type.
The `R.cmd 1` expression tries to break the abstraction by assuming that the `R` implementation is using the `int` type as an underlying implementation. Imagine, what will happen if the `Net.cvt` field contained another implementation,
for example
module Cmd = struct
type message = string
let cmd = print_endline
end
let i = { Net.cvt = (module Cmd: CmdIface) }
Net.net i
This will finally lead to a call `print_endline 1` if the type system won't stop you before.
The solution is either to uncover the abstractions and stick to `int` as a concrete representation of the message abstraction or to extend the message abstraction interface with functions that will allow you to create the messages, e.g.,
module type CmdIface = sig
type message
val of_int : int -> message
val cmd : message -> unit
end