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