# 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:** 5
**Page:** 2

<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:54pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/21 "2021-09-22T15:54:24Z")

</div>

Ok, that makes sense. I was mislead by this example: [Managing functor dependencies - #11 by n4323](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/11) which seemed to show that inside the functor, the full argument module is available without constraint.

So my current understanding is: in

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

```

the module type of `F(X).M` is `S` but no type equalities link `M` to `X`. If I want them I have to use an `with` constraint, or use `X` inside `F` unchanged.

My remaining problem actually refers to functor application inside another functor. I’ll try a shortened version:

```ocaml
module F1 (X:S) = struct ... end
module F2 (X:S) = struct module F1_ = F1 (X) ... end
module X_ = struct ... end
module F1_ = F1 (X_)
module F2_ = F2 (X_)

```

Now I want `F2_.F1_` to be compatible with `F1_`. Somehow the compiler thinks otherwise. What can I do?  
(The functors live in different compilation units, so they have signatures explicitly written in .mli files.)

---

<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, 4:13pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/22 "2021-09-22T16:13:19Z")

</div>

This small example:

```ocaml
module type s = sig type t val x: t end
module F(X:s) = struct module Y = X end
module F2(X:s) = struct module Z = F(X) end

module X: s = struct
  type t = int
  let x = 0
end

module FX = F(X)
module F2X = F2(X)
let eq = FX.Y.x = F2X.Z.Y.x

```

works as expected. The problem is thus in the signature that you have written, they are most probably hiding some type equality. This is the reason why I am generally advising to start by looking at the inferred signature for functors before writing down the explicit interface.

As an illustration, the signature for the above example to allow `eq` to type would be something like:

```ocaml
module type s = sig type t val x: t end
module F(X:s): sig module Y: s end = struct module Y = X end
module F2(X:s): sig
  module Z: sig
     module Y: s with type t = F(X).Y.t
   end
end = struct
  module Z = F(X)
end

```

But even in this case, the equality between `F(X)` and `F2(X).Z ` is lost at the module frontier.

---

<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 23, 2021, 9:39am UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/23 "2021-09-23T09:39:32Z")

</div>

Thanks, that’s helpful. Maybe I can get further by looking at inferred functor signatures in the original code.

Dealing with signature constraints feels like a hairy business. For instance, I tried `X.x = FX.Y.x` in your first, unconstrained example which passes. In the second example it does not. I can see why: applying `s` makes a fresh type for `Y.t`. Actually, the inferred signature for `FX` in the unconstrained example is `sig module Y: sig type t = X.t val x: t end end`, so the type equality with the input `X.t` is indeed inferred. To rescue that in a signature I would have to constrain like this: `module F(X:s) : sig module Y: s with type t = X.t end`

My feeling is that repeating such equalities for each type in (nested sub)modules would not scale well to bigger functors?

[Edit:] Actually, the signature ` sig module Y: s end with module Y = X` for `F(X:s)` also works. Maybe `with module` annotations are more scalable.

---

<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 23, 2021, 3:45pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/24 "2021-09-23T15:45:09Z")

</div>

Ok, I finally got it to compile! Thanks so much to all for your help and considerable patience!

I started by looking at the inferred module interfaces, and then introducing a module signature with a `with type trouble = ...` constraint for exactly the type `trouble` that was making problems further down. The mismatching types had exactly the same explicit representation, just derived by different functor applications, which seemed really odd and persuaded me that the problem must be elsewhere.

After poking around, and by luck, I discovered a re-export of the form:

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

```

deeper down in the module dependency chain.  
I removed the unnecessary re-export for purely esthetic reasons. I then had to replace all uses of the re-export by just the input module. This made my project compile again! Yay!  
I now believe that because ` X: sig type t ... end` has an abstract type `t`, different instantiations of `F` became incompatible, as `t` was generated fresh each time. So indeed early answers by @Drup and @octachron contained the answer, it was just difficult to locate the actual place where the error happened.

---

<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 24, 2021, 1:11pm UTC](https://discuss.ocaml.org/t/managing-functor-dependencies/8510/25 "2021-09-24T13:11:57Z")

</div>

Hopefully, transparent ascription will help with many similar situations by exposing a finer-grained and more robust notion of module aliases.

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