Are there any tips for organizing the OCaml code to avoid nest hell?

As i writting more and more OCaml code(the same as ReScript), i felt more and more tired to write the code. The module system is very expressive for me, but the function call chain is too long when i call the function behind a module which is nested deeply, creating a module to alias the nested module can ease this issue in some extents.

1 Like

You already point to the best solution in my book: a short alias to a long module path.

Two complements:

First, if you end up using the same abbreviations in many modules in a library, a convention I follow in this case is to have a module Abbrevs to contain them, that I open in the modules using them.

Second, if these long module paths come from your own code, in some cases it can be an indication that some interface improvements are in order. Maybe the englobing module should already be exposing this type/value bound to a shorter (and easier to find) name.
As in instead of A.Sub.X.of_a, export type x = Sub.X.t and A.to_x.
This is what is done in dream for instance.

1 Like

When I see that a function grow bigger, I try to make local and more concrete abstractions for the operations it does.
For example, from this:

type t = {
  a : int Mylib.Mymodule.t;
  b : string Mylib.Mymodule.t;
}

let something t =
  (* opening Mylib.Mymodule is not great because there's already so much in scope *)
  Mylib.Mymodule.generic_operation a ...

to this:

module A = struct
  (* This module has a smaller scope, which allow me to open other modules *)
  open Mylib.Mymodule

  type nonrec t = int t

  let concrete_operation t =
    generic_operation t ...
end

type t = {
  a : A.t;
  b : B.t;
}

let something t =
  A.concrete_operation a ...
1 Like