F# uses .NET classes and objects for a module system, so your use of Objects for "services" is not surprising. An OCaml programmer is much less likely to miss Objects and DI frameworks, as OCaml has a powerful module system (i.e. module functors).
Free Monads can reify an effectful computation, giving flexibility on how it is interpreted. But they are not really a substitute for a good module system.
Okay I think I get free monads now. They seem pretty awesome, essentially letting you plug in an interpreter for the function you're going to run. I can see high-level how this would appear to be a great generic DI option--you set up an "interpreter" to handle the statements in your function however you want: for reals, for test, for reals with logging, etc. And automagically everything gets executed exactly how you want with no additional cruft.
What makes me cautious about the concept though is that e.g. `do_x_and_y()` would be interpreted differently than `do_x(); do_y()`, even if they were fundamentally the same. While "so what?" is a perfectly valid response, that little tidbit just makes me feel like, while FM's are a very cool abstraction for something, it's not really ideal for DI. It's just something meant for a different level. The article "The Wrong Abstraction" comes to mind.
> ... you set up an "interpreter" to handle the statements in your function however you want: for reals, for test, for reals with logging, etc.
That is the tip of the iceberg of free monads. Their full power lies in being able to combine different type sof effects into more powerful, composed effects. E.g. you want to do IO while also processing probability distributions using a probability monad. But they can get pretty hairy. See https://youtu.be/qaAKRxO21fU for the gory details.
The monad laws guarantee that there's no difference between do_x(); do_y(); and do_x_and_y(); where the latter is defined as { do_x(); do_y() }. In fact, monads would be pretty useless if that were not the case.
Out of curiosity, OCaml also has traditional classes/interfaces/objects, right? If so, then how do you decide when to use those versus module functors?
Modules and functors are able to contain type definitions, while classes/objects are not. This makes modules practically much more useful for abstraction.
AFAIK no one uses Objects in OCaml as the module system is sufficiently powerful. The Mirage project is a good example of using OCaml module functors to specialise components.
Free Monads can reify an effectful computation, giving flexibility on how it is interpreted. But they are not really a substitute for a good module system.