# Managing functor dependencies

**URL:** https://discuss.ocaml.org/t/managing-functor-dependencies/8510
**Category:** Learning
**Created:** [September 20, 2021, 7:56pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510 "2021-09-20T19:56:02Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 20, 2021, 7:56pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/1 "2021-09-20T19:56:02Z")

</div>

I’m confused about how to handle module equalities when building up a hierarchy of functor applications. Here is a shortened version of my situation:

```ocaml
module A = (struct module Asub end : SA)
module B = (struct module Bsub end : SB)
module C (A:SA) (B:SB) = struct module A = A module B = B ... end
module D (A:SA) (B:SB) = struct module C' = C (A) (B) ... end

```

In reality, `D` is a sort of add-on module providing optional functionality that is sometimes needed. Then I have both an instance of `C` and and instance of `D` available at top-level:

```ocaml
module Ctop = C (A) (B)
module Dtop = D (A) (B)

```

and I would like to ensure that `C'` inside `Dtop` and `Ctop` are seen as identical. I tried something along the lines of

```ocaml
module Dtop_ = D (A) (B)
module Dtop = (Dtop_ : module type of Dtop_ with module C' = Ctop) 

```

but this is rejected because of missing type equalities in submodules of `C'` (at least that’s how I interpret the errors).

How can I handle this situation in an ergonomic way? Or can I restructure the hierarchy in a simpler way?

FWIW, For the functionality in `D` I actually only need the values in `C`. I made `D` a functor of `A` and `B` only because I don’t have an input signature for a `C` argument available: the functor `C` is not applied yet with concrete inputs when `D` is defined.

* * *

[Edit] TL; DR for posterity: The root cause was that in

```ocaml
module F (X:S) : sig
   module X : S
 = struct 
  module X = X 
end

```

`X.t` and `F(X).X.t` are not known to be the same type. If `X.t` is abstract, they will be incompatible! For this reason, re-exporting input modules from functors requires great care in adding type equalities and is perhaps best avoided!

---

<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: [September 20, 2021, 8:40pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/2 "2021-09-20T20:40:10Z")

</div>

Maybe you could do

```auto
module Dtop = D (A) (B)
module Ctop = Dtop.C'

```

?

Otherwise, this is kinda weird but `module type of struct include M end` can have more equalities than `module type of M` so maybe `module Dtop = (Dtop_ : module type of struct include Dtop_ end with module C' = Ctop)` would work.

---

<div class="post-metadata">

### Author: ![SpiceGuid](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/spiceguid/32/2752_2.png) [@SpiceGuid](https://discuss.ocaml.org/u/SpiceGuid)
#### Post date: [September 20, 2021, 8:44pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/3 "2021-09-20T20:44:20Z")

</div>

May be you should restart your module hierarchy from zero, using the `include` keyword this time (no functors needed).

> [@n4323](#):
>
> `D` is a sort of add-on module providing optional functionality that is sometimes needed.

It sounds like the module C is actually not needed anywhere because the module D is a valid replacement.

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 8:27am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/4 "2021-09-21T08:27:56Z")

</div>

> [@SkySkimmer](#):
>
> ```auto
> module Dtop = D (A) (B)
> module Ctop = Dtop.C'
> 
> ```

Yes, I think this would work. But it’s contrary to the importance/size of the modules: `C` is used often and is big, `D` is small and used only sometimes as an add-on, typically further down in application code.

> [@SkySkimmer](#):
>
> `module Dtop = (Dtop_ : module type of struct include Dtop_ end with module C' = Ctop)`

That’s interesting and mysterious: why/when is `struct include D end` something different than `D`? I could see a difference if `D` is constrained by a signature perhaps?

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 8:31am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/5 "2021-09-21T08:31:30Z")

</div>

> It sounds like the module C is actually not needed anywhere because the module D is a valid replacement.

I would like to keep `D` optional. It contains specialized functionality that’s not needed most of the time when using `C`.

---

<div class="post-metadata">

### Author: ![jjb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jjb/32/2713_2.png) [@jjb](https://discuss.ocaml.org/u/jjb)
#### Post date: [September 21, 2021, 9:17am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/6 "2021-09-21T09:17:45Z")

</div>

> [@n4323](#):
>
> why/when is `struct include D end` something different than `D` ?

This is discussed briefly in the [manual](https://ocaml.org/manual/moduletypeof.html#s:module-type-of). The crux of the distinction is that `module type of struct include D end` produces a signature where the type (and module?) fields are strengthened with equations to their correspondents in `D`, while `include module type of D` more literally includes the inferred signature or `D`, without strengthening it with equations back to `D`.

---

<div class="post-metadata">

### Author: ![Drup](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/drup/32/35_2.png) [@Drup](https://discuss.ocaml.org/u/Drup)
#### Post date: [September 21, 2021, 9:24am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/7 "2021-09-21T09:24:32Z")

</div>

Can you show an actual simplified example that (fails to) compile, including the exposed types of `C` and `D` ? What you want is perfectly possible thanks to applicative functors, but it depends on the details of the various module types involved.

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 12:21pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/8 "2021-09-21T12:21:50Z")

</div>

Ok, i managed to put together an example which I think shows the same problem. In so doing, I also learned that `module F (I:S) = struct module I = I end` does not actually constrain the signature of `F.I` to `S` which came as a surprise to me. Anyway, after adding signatures inside of functor bodies, I ended up with this:

```ocaml
module type SA = sig type t val of_int: int -> t val print: t -> unit end
module A = struct
  type t = int
  let of_int i = i
  let print = print_int
end
module B (A:SA) = struct
  module A = (A:SA)
  let print_twice i = A.print i; A.print i
end
module C (A:SA) = struct
  module A = (A:SA)
  module Bsub = B (A)
  let a = Bsub.A.of_int 5
end
module Btop = B (A)
module Ctop = C (A)

let _does_not_work = Btop.print_twice Ctop.a

```

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 12:33pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/9 "2021-09-21T12:33:40Z")

</div>

Actually a simpler example of the same thing may be

```ocaml
module type SA = sig type t val of_int: int -> t val print: t -> unit end
module A = (struct
  type t = int
  let of_int i = i
  let print = print_int
end : SA)
module B (A:SA) = struct
  module A = (A:SA)
  let print_twice i = A.print i; A.print i
end
module Btop = B (A)

let _does_not_work = Btop.print_twice (A.of_int 3)

```

One thing I tried was

```ocaml
module Btop' = (Btop: module type of Btop with module A = A)

```

but this is also rejected

---

<div class="post-metadata">

### Author: ![Drup](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/drup/32/35_2.png) [@Drup](https://discuss.ocaml.org/u/Drup)
#### Post date: [September 21, 2021, 12:51pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/10 "2021-09-21T12:51:13Z")

</div>

So, there are sort of several issues. They all stem from the fact that, from the point of view of the module system and equalities of modules `(M : T) ≠ M`. Let’s detail:

1. You over annotate your module types. Unlike what you said, `A` will be constrained by `SA` inside the module, but with additional type equalities. Your type annotation only make it so that `B.A ≠ C.A ≠ int`. As a consequence, if you replace `module A = (A : SA)` by `module A = A`, it immediately works. The type infered will be of the form `module A : module type of A`, which is fully correct.

2. In your first example, the problem is not directly that `C(A).Bsub ≠ B(A)`, but rather that `C.A ≠ B.A` (since you re-annotated, see the previous remark). Applicativeness then fails. This is because your rebind `A` and hide its type. If you replace `C` (without changing B!) by a less ambiguous version as below, it works:

```auto
module C (AOrig:SA) = struct
  module A = (AOrig:SA)
  module Bsub = B (AOrig)
  let a = Bsub.A.of_int 5
end

```

In this case, we see clearly that `C(A).Bsub.A = B(A).A = A` thanks to the applicative behavior of functors.

Note that there is a WIP extension of the module system called “transparent ascriptions”, written `(M <: T)`, which probably corresponds more to your understanding of what module type constraints should do: `(M <: T)` preserve equalities on `M`. In that case, the module system knows that `M = (M <: T)` (but with a “filtered view”).

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 1:08pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/11 "2021-09-21T13:08:20Z")

</div>

Thanks for the explanations. You’re right that removing the `:SA` constraint in the body of `B` makes it compile. Great!

As I try to understand the logic here, some comments:

> [@Drup](#):
>
> Unlike what you said, `A` will be constrained by `SA` inside the module, but with additional type equalities.

I wrote this because in the following example:

```ocaml
module type SA = sig type t val of_int: int -> t val print: t -> unit end
module A = struct
  type t = int
  let of_int i = i
  let print = print_int
end
module B (A:SA) = struct
  module A = A
  let print_twice i = A.print i; A.print i
end
 
module Btop = B (A)

```

the type of `Btop.print_twice` is inferred as `int -> unit`. So `(A:SA)` in the functor input signature is not enough to make the type abstract when the functor is applied.

---

<div class="post-metadata">

### Author: ![Drup](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/drup/32/35_2.png) [@Drup](https://discuss.ocaml.org/u/Drup)
#### Post date: [September 21, 2021, 1:29pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/12 "2021-09-21T13:29:59Z")

</div>

Sure, since `A.t = int`. Do you want to make `A.t` abstract, or for the functors `B` and `C` to hide their argument ?

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 21, 2021, 4:09pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/13 "2021-09-21T16:09:56Z")

</div>

I wanted to make `A.t` abstract because in the real code `A` is a functor and `A.t` is a record with fields whose types are inherited from the functor arguments. So outside modules would not know how to work with values of type `A.t` anyway.

[Edit]: One basic thing I don’t understand, related to your comment

> `A` will be constrained by `SA` inside the module, but with additional type equalities. Your type annotation only make it so that `B.A ≠ C.A ≠ int` .

is the following:

```ocaml
module A = (struct ... end : SA)
module B (A:SA) = struct module A = A end
module B_constrained (A:SA) = struct module A = (A:SA) end

```

Why is `B_constrained` different from `B`? To me it would seem natural to think: “A already has module type SA, so nothing more can happen if I constrain it again to the same signature.” This sounds right to me (regular types work like this afaict) but it is incorrect. In fact `B_constrained.A` is inferred to be of `sig type t = B_constrained(A).A.t ...end` while `B.A` is just of `sig type t = A.t`.

[Edit2]: After reading your entire post, it seems that the proposed `(A<:SA)` may indeed correspond to my expectation.

[Edit3]: Is this a more correct way of thinking about signature constraints: " Each time I constrain a module as `M:SA` a fresh type `t` is generated and ascribed to `M.t`? This then would break the identity of types even when the same module is constrained twice. This seems to be more or less correct, because the following fails

```ocaml
module A1 = (A:SA)
module A2 = (A:SA)
let _ = A2.print (A1.of_int 3)

```

[Edit4] … and of course by reading _very_ attentively [the manual](https://ocaml.org/manual/modtypes.html#sss:mty-type) one could have guessed this. It certainly was new to me.

---

<div class="post-metadata">

### Author: ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)
#### Post date: [September 22, 2021, 9:17am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/14 "2021-09-22T09:17:54Z")

</div>

Signature constraints make a fresh copy of the constrained modules. In other words, in

```ocaml
module M : S = Original

```

the module `M` is a new module unrelated to `Original`, and the only type equalities between the components of `M` and `Original` are the one explicitly present in `S` (for instance if `S` is ` sig type t = Original.t end`.

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 22, 2021, 12:42pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/15 "2021-09-22T12:42:24Z")

</div>

So, loosely speaking, “module type constraints can break applicativity.”

I’m trying to apply this insight to solve my original problem. Somehow the signature requirements still get in the way. Here is another version of what I think one of my problems still is.

file basic.mli

```ocaml
module type S = sig 
  type t
  val v : t
  val f : t -> unit
end
module Bd (V:S) : sig 
  module V : module type of V 
  ... 
end

```

file basic.ml

```ocaml
module type S = sig ... end
module Bd (V:S) = struct 
  module V = V 
  ... 
end

```

The functor `Basic.Bd` is then called in another functor taking the same arguments, which is meant to extend the functionality in some situations.

file extension.mli

```ocaml
module O (V:Basic.S) : sig
   module V : module type of V
   module Bd : module type of Basic.Bd (V)
end

```

file extension.ml

```ocaml
module O (V:Basic.S) = struct
   module V = V
   module Bd = Basic.Bd (V)
end

```

now trying to use these modules, in a file application.ml, gives me trouble:

```ocaml
module V_ = struct ... end
module O_ = Extension.O (V_)
module Bd_ = Basic.Bd (V_)
let _fails = O_.Bd.V.f Bd_.V.v

```

The error message complains that `Bd_.v` has type `Bd_.t` while `E_.Bd.t` was expected.

I was able to get rid of this particular error by adding `with module V = V` after the signature of `Bd` in basic.mli. It’s not clear to me why this is needed. Is it because the signature in the .mli acts as a constraint generating fresh types? I don’t want that! But I see no way to get around it since I need to put some signature for `Bd` in basic.mli in order for it to appear to the outside!

---

<div class="post-metadata">

### Author: ![jjb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jjb/32/2713_2.png) [@jjb](https://discuss.ocaml.org/u/jjb)
#### Post date: [September 22, 2021, 2:25pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/16 "2021-09-22T14:25:45Z")

</div>

In:

> [@n4323](#):
>
> ```ocaml
> module Bd (V:S) : sig 
> module V : module type of V 
> ... 
> end
> 
> ```

I wonder if the aliasing is not helping. Consider that this is equivalent to:

```ocaml
module Bd (W:S) : sig 
  module V : module type of W 
  ... 
end

```

In particular, `module V : module type of V` does not guarantee that the `V` module returned by the `Bd` functor has anything to do with the argument of the functor, other than that they both happen to satisfy the same signature. That is not enough for applicativity. For that you need that the returned module is the same as the argument one. Perhaps it would work to use:

```ocaml
module Bd (V:S) : sig 
  module V = V 
  ... 
end

```

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 22, 2021, 2:50pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/17 "2021-09-22T14:50:54Z")

</div>

Unfortunately that does not help. When I replace `module V : module type of V` by `module V = V` in basic.mli, I get a complaint about signature mismatch between

```auto
    File "basic.ml", line 49, characters 2-14:
         Definition of module V/1
       File "_none_", line 1:
         Definition of module V/2

```

which is rather enigmatic. (I have also removed the `with module V = V` constraint)

As a side remark, just to show that in principle all module types are compatible, I can follow @SkySkimmer 's advice and define `module Bd_ = O_.Bd` in the application file, which fixes the problems but seems like a kludge. It would be more satisfying to be able to have “applicativity all the way through” the functor stack. Or at least to know what would be required to get it or else why it may not be a good idea.

[Edit:] I have also now tried to rename the argument in order to remove shadowing. the version with `module Bd (W:S) = struct module V = W ... end` and `module Bd (W:S) : sig module V : S ... end` does seem to work without `with` constraint! So that’s some progress. Shadowing may have messed something up (although I can’t see where it could have, at present)

---

<div class="post-metadata">

### Author: ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)
#### Post date: [September 22, 2021, 3:23pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/18 "2021-09-22T15:23:22Z")

</div>

First, you should avoid `module type of ` as much as possible. In particular

```ocaml
module Bd (V:S) : sig 
  module V : module type of V 
end

```

is a verbose way to write

```ocaml
module Bd (V:S) : sig 
  module V : S 
end

```

Then in general, you cannot create alias of arguments functor inside the functor. Any code looking like

```ocaml
module F(X:S) = struct
  module M = X
end

```

creates a new module `M` which is unrelated to the original argument.

---

<div class="post-metadata">

### Author: ![n4323](https://avatars.discourse-cdn.com/v4/letter/n/97f17d/32.png) [@n4323](https://discuss.ocaml.org/u/n4323)
#### Post date: [September 22, 2021, 3:31pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/19 "2021-09-22T15:31:20Z")

</div>

Fair enough about the unnecessary `module type of`.

> [@octachron](#):
>
> creates a new module `X` which is unrelated to the original argument.

did you mean a new module `M` ? What if I wanted to re-export a module? For example  
if `module F_ = F (X)` so that `F_.M` is interchangeable with `X` ?

---

<div class="post-metadata">

### Author: ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)
#### Post date: [September 22, 2021, 3:33pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/20 "2021-09-22T15:33:55Z")

</div>

Yes, I meant `M`.  
You can’t re-export an argument (without transparent module ascription) because you don’t have a full view of the argument, only a slice constrained by the argument signature.

[Next page](https://discuss.ocaml.org/t/managing-functor-dependencies/8510.md?page=2)
