Single-function functors or first-class modules in function arguments?

Hi all,

Suppose I want to make a function that takes a module parameter. I can think of two ways to do it: either I wrap the function inside a functor:

module On_monad (M : Monad.S) = struct
    let map_m x ~f = (* something using M *)
end

module OM = On_monad (M)
let foo = OM.map_m (* ... *)

Or I pass the module as a first-class module into the function:

let map_m (module M : Monad.S) x ~f = (* something using M *)

let foo = map_m (module M) (* ... *)

What I don’t know is the relative performance and idiomatic-ness tradeoff of these two solutions. Is there always a noticeable performance hit to using first-class modules? Naively I presume that the latter will need resolving at run-time whereas the former can be resolved at compile time, but I don’t actually know what the OCaml compiler would do.

Furthermore, since the second alternative is significantly easier to work with in situations where I only use map_m with monad M once, are there perf reasons against adding doing this the first way (and maybe adding more functions to On_monad, and then writing a helper function as follows?

let map_m (module M) x ~f =
  let module OM = On_monad (M) in
  OM.map_m x ~f
4 Likes