Recursive modules and Base's Map.M()

base

#1

I’m trying to construct a variant type which contains a map that uses the variant type as a key.

open Base
module rec T : sig
  type t =
    | Int of int
    | Table of t Map.M(T).t
  [@@deriving compare, sexp]
  include Comparator.S with type t := t
end = struct
  type t =
    | Int of int
    | Table of t Map.M(T).t
  [@@deriving compare, sexp]
  include Comparator.Make(T)
end
include T

I’ve been using the Map module from Base, but I’m running into an error:

Error: Cannot safely evaluate the definition
   of the recursively-defined module T

I think this is because Comparator.Make() creates a val comparator : (t, comparator_witness) comparator so T isn’t a safe module. Any ideas on how to get around this?


#2

I came up with a workaround, but I have little experience with Base, Core and TypeConv and so not sure this corresponds to the intended use of the libraries in such cases:

open Base

module type T0 = sig type t [@@deriving compare, sexp] end;;

module rec T0 : sig
  type comparator_witness
  type t =
    | Int of int
    | Table of (T0.t, t, comparator_witness) Map.t
  [@@deriving compare, sexp]
  val comparator : unit -> (t, comparator_witness) Comparator.t
end = struct
  module U = struct include (T0 : T0 with type t = T0.t) include Comparator.Make (T0) end
  type t =
    | Int of int
    | Table of t Map.M (U).t
  [@@deriving compare, sexp]
  type comparator_witness = U.comparator_witness
  let comparator () = U.comparator
end;;

module T1 = struct include T0 let comparator = T0.comparator () end;;

module T = struct
  type t = T1.t =
    | Int of int
    | Table of T1.t Map.M(T1).t
  include (T1 : module type of T1 with type t := t)
end;;

T.compare (T.Int 0) (T.Table (Map.of_alist_exn (module T) [T.Int 0, T.Int 1]));;

T.sexp_of_t (T.Table (Map.of_alist_exn (module T) [T.Int 0, T.Int 1]));;