Most idiomatic way to reference module in signature?

Hello,

In my codebase I have a few modules that are parametric on a monad. Some of them are also functors, and receive other parameters that are parametric on this monad, and all arguments must match.
I see two solutions to enforce that.

First solution:

module type Param = sig
  module MyMonad
  ...
end

module F
  (M: MyMonad)
  (P: Param with module MyMonad = MyMonad) =
struct ... end

Second solution:

module Param (M: MyMonad) = struct 
  module type S = sig ... end
end

module F
  (M: MyMonad)
  (P: Param(MyMonad).S) =
struct ... end

I prefer the second one, it’s easier to instantiate.
But 1) is this some footgun I can’t see coming and 2) is there a more idiomatic way of doing this?

6 Likes

The lack of answers makes me more worried that I’m doing something entirely wrong and unusual here :sweat_smile:

I have used both approaches, and they do work.

As far as I can see, the first variant is quite more common.
However I would recommend to use a destructive substitution in this case

module F
  (M: MyMonad)
  (P: Param with module MyMonad := MyMonad) = ...

to avoid carrying around copies of modules (which can interfere with applicative functors).

Personally, I tend to switch to the functor variant once the module type dependencies start to get complicated.

2 Likes

Great thank you very much!
Didn’t think about the destructive subst for some reason :thinking: