For example I have the code that wants to abstract the nature of buffer types, lets take just string and bytes for the simplicity:
open Core
module type Byteable = sig
type t
val length: t -> int
val to_bytes: t -> bytes
end
module StringB : sig
type t
val length: t -> int
val to_bytes: t -> bytes
end
module BytesB: sig
type t
val length: t -> int
val to_bytes: t -> bytes
end
module StringB : Byteable = struct
include String
let to_bytes = Bytes.unsafe_of_string_promise_no_mutation
end
module BytesB: Byteable = struct
include Bytes
let to_bytes a = a
end
Then if I define a functor, something like:
(* this one just to clarify it always accepts bytes *)
val call_some_function : bytes -> unit
module Make_stuff (M : Byteable) = struct
let do_some_weird_stuff ~data =
let databytes = M.to_bytes data in
call_some_function databytes
end
module MyBytes = Make_stuff (BytesB)
module MyString = Make_stuff (StringB)
With just this it compiles fine and well. But if I actually try to use the resulting modules function do_some_weird_stuff it requires BytesB.t type instead of bytes or StringB.t type instead of string.
For example if I call something like:
let cool_string = "something" in
MyString.do_some_weird_stuff ~data:cool_string
will produce a compile error:
this expression has type string but an expression was expected of type StringB.t
module StringB : sig
type t
val length: t -> int
val to_bytes: t -> bytes
end
make the type StringB.t abstract. Thus outside of the module StringB, the only information known about t is that, it can be consumed by StringB.length or StringB.to_byte. In particular, there is no way to construct a value of type t from types outside of the module.
If you want to expose the fact that StringB.t = string, you need to state this equality in the signature explicitly:
module StringB : sig
type t = string
val length: t -> int
val to_bytes: t -> bytes
end
module StringB : sig
type t = string
val length: t -> int
val to_bytes: t -> bytes
end
but it complains that this doesn’t match to the module type:
The implementation does not match the interface ....:
In module StringB:
Type declarations do not match:
type t = StringB.t
is not included in
type t = string
module StringB : Byteable = struct
include String
let to_bytes = Bytes.unsafe_of_string_promise_no_mutation
end
module BytesB: Byteable = struct
include Bytes
let to_bytes a = a
end
So you have the same problem with Byteable which is not an usable module type by itself, you most probably want Byteable with type t = string (and Byteable with type t = concrete_type for other implementations).
Thanks, this did the job. But the original idea was to derive the type from the String or Bytes modules (string and bytes types), is this possible somehow?