Hello! I’m cleaning up the rough edges of how I’ll be using OCaml starting this year. The situation below isn’t like anything I’ve seen around here, so I thought it could be worth a post.
What I’m trying to do: I have an
Intf.ml in my library, containing common module signatures like
Jsonable. With this scheme, I’m explicit about implementing those conventions and it avoids duplicating those declarations and doc-comments. In the case of
Jsonable however, the
of_json functions are usually the same, so I’d like to provide that implementation, but its implementation depends on the modules’ specific
(* intf.ml *) open! Base module type Printable = sig type t val pp : t -> string end module type Jsonable = sig type t val to_json : t -> string val of_json : string -> (t, [> `JsonError of string ]) Result.t val to_yojson : t -> Yojson.Safe.json val of_yojson : Yojson.Safe.json -> (t, string) Result.t end module Json = struct let to_json to_yojson a = a |> to_yojson |> Yojson.Safe.to_string let of_json of_yojson s = try match s |> Yojson.Safe.from_string |> of_yojson with | Ok v -> Ok v | Error e -> Error (`JsonError e) with | Yojson.Json_error e -> Error (`JsonError e) ;; end (* stuff.mli *) type t include Intf.Jsonable with type t := t include Intf.Printable with type t := t val of_int : int -> t (* stuff.ml *) type t = int [@@deriving yojson] (* Adds of_yojson and to_yojson *) let to_json = Intf.Json.to_json to_yojson let of_json = Intf.Json.of_json of_yojson let pp s = Int.to_string s let of_int i = i
of_json is a very usable solution, but I’m disappointed with two aspects:
Is there a way around creating that second
Jsonmodule in the namespace for stashing those two functions? I see nothing obvious.
I wish I could “include” something in
stuff.mlt avoid declaring those two bindings entirely. I looked into learning about functors for this (especially with flambda promising to reduce/eliminate their run-time cost), but they seem to work backwards from what I’m trying to achieve: I want my various modules like
Stuffto implement several interfaces as needed, some of which may include some helpful implementation bits. Functors would have to be used by the users of my modules to possibly achieve this, but I actually want to provide them with
Stuffready to use.
Am I missing something, or have I already reached the simplest solution with these compromises?