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).