Stephen taught me a neat trick a while back. Suppose you want to define a some mutually recursive types

type even = Zero | Even_succ of odd
and odd = Odd_succ of even

Now suppose you want to do this in such a way that each type belongs to its own module. Since OCaml requires signature annotations in recursive module definitions, I thought this required one to write out the type definitions twice.

module rec Even : sig
  type t = Zero | Succ of Odd.t
end = struct
  type t = Zero | Succ of Odd.t
end
and Odd : sig
  type t = Succ of Even.t
end = struct
  type t = Succ of Even.t
end

However, Stephen showed me the following trick

module rec Even : sig
  type t = Zero | Succ of Odd.t
end = Even
and Odd : sig
  type t = Succ of Even.t
end = Odd

Whoa! We’re seemingly defining some modules out of thin air! This looks very analogous to the ill-founded definitions

let rec even : some_type_for_even = even
  and odd : some_type_for_odd = odd

But since we’re only defining types here, this trick cannot cause undefined values to sneak into our program. We have effectively gotten OCaml to infer the definition of a module from its signature in the special case where the module only contains type definitions (it may also contain module type definitions).

Mutual recursion is not required for this to work. You can also wrap everything up into a single recursively defined parent module if you like.

module rec Layered : sig
  module Even : sig
    type t =
    | Zero
    | Succ of Layered.Odd.t
  end
  module Odd : sig
    type t =
    | Succ of Layered.Even.t
  end
end = Layered

Sadly, this trick is somewhat limited in that it doesn’t work with our Type_conv pre-processors since there are only type specifications here and not type definitions upon which to hang a “with sexp” (for example).