# Module type constraints in first class modules

**URL:** <https://discuss.ocaml.org/t/module-type-constraints-in-first-class-modules/16155>\
**Category:** Learning\
**Tags:** first-class\_modules\
**Created:** [February 20, 2025, 10:31am UTC](https://discuss.ocaml.org/t/module-type-constraints-in-first-class-modules/16155 "2025-02-20T10:31:05Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![dlesbre](https://avatars.discourse-cdn.com/v4/letter/d/bbce88/32.png) [@dlesbre](https://discuss.ocaml.org/u/dlesbre)\
**Post date:** [February 20, 2025, 10:31am UTC](https://discuss.ocaml.org/t/module-type-constraints-in-first-class-modules/16155/1 "2025-02-20T10:31:05Z")

</div>

I’ve stumbled into a weird situation recently when using first-class modules. For context, I have to functors with the same type, and I would like to choose one dynamically at run time:

```auto
module type BAR = sig type 'a t end
module type FOO = sig module Bar : BAR end

(** 2 functors which look a bit like this *)
module F1(B : BAR) : FOO with module Bar = B = _
module F2(B : BAR) : FOO with module Bar = B = _

```

The problem comes when trying to choose which functor to us while keeping the information that the resulting `FOO` module verifies `module Bar = B`.

Essentially, I would like to be able to do something like this:

```auto
let f cond (module B : BAR) =
  let module G = (val 
      if cond then (module F1(B)) else (module F2(B))
      : FOO with module Bar = B) in
  () (* G is used here *)

```

However, this gets rejected with the error message `invalid package type: only 'with type t =' constraints are supported`. Similarly, the constraint directly on the type also fails with a similar error message:

```auto
let f' cond (module B : BAR) =
  let module G = (val 
    if cond then (module F1(B)) else (module F2(B)) 
    : FOO with type 'a Bar.t = 'a B.t) in
  () (* G used here *)

```

If the argument module `B ` is statically known, then I can do something like this:

```auto
module B : BAR = _
module type FOO_WITH_B = FOO with module Bar = B

let f cond =
  let module G = (val 
    if cond then (module F1(B)) else (module F2(B)) 
    : FOO_WITH_B) in
  () (* do something with G here *)

```

Which is a bit ugly but somewhat manageable. However, in my case, the `B` module is also chosen dynamically… This lead me to the following ugly hack, in which I use a second functor just to generate my signature:

```auto
module GenType(B : BAR) = struct
  module type T = FOO with module Bar = B
end

let f cond (module B : BAR) =
  let module G = (val 
    if cond then (module F1(B)) else (module F2(B)) 
    : GenType(B).T) in
  () (* G used here*)

```

Is there any cleaner way to do this?

Also is there any rationale behind the restriction of constraints on packaged module types , or is it just something that wasn’t implemented?

---

<div class="post-metadata">

**Author:** ![SkySkimmer](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/skyskimmer/32/1672_2.png) [@SkySkimmer](https://discuss.ocaml.org/u/SkySkimmer)\
**Post date:** [February 20, 2025, 11:13am UTC](https://discuss.ocaml.org/t/module-type-constraints-in-first-class-modules/16155/2 "2025-02-20T11:13:14Z")

</div>

you can do

```auto
let f cond (module B : BAR) =
  let module M = (struct module type T = FOO with module Bar = B end) in
  let module G = (val
      if cond then (module F1(B)) else (module F2(B))
      : M.T) in
  () (* G is used here *)

```

I don’t think there’s a `let module type` so we need an enclosing module M.

The enclosing module can be made anonymous with `open struct`:

```auto
let f cond (module B : BAR) =
  let open (struct module type T = FOO with module Bar = B end) in
  let module G = (val
      if cond then (module F1(B)) else (module F2(B))
      : T) in
  () (* G is used here *)

```

---

<div class="post-metadata">

**Author:** ![smuenzel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/smuenzel/32/3945_2.png) [@smuenzel](https://discuss.ocaml.org/u/smuenzel)\
**Post date:** [February 28, 2025, 8:59pm UTC](https://discuss.ocaml.org/t/module-type-constraints-in-first-class-modules/16155/3 "2025-02-28T20:59:59Z")

</div>

What about something like this:

```auto
module type BAR = sig type 'a t end
module type FOO = sig module Bar : BAR end
module type FUNCTOR = functor (B : BAR) -> FOO with module Bar = B

module F1 : FUNCTOR
module F2 : FUNCTOR

let f cond (module B : Bar) =
  let (module Fc) = if cond then (module F1 : FUNCTOR) else (module F2 : FUNCTOR) in
  let module G = Fc(B) in
  

```
