I'm trying to figure out a way to hide certain helper functions and related stuff from the user of a module and thought using an IIFE would work, yet it fails because a type variable cannot be generalized?
I think I've boiled it down to the most basic scenario with the following code:
module TestA = {
let y = 0;
let x = (type a, numbers: list(a)): option(a) => None;
};
module TestB = {
let x =
(
() => {
let y = 0;
(type a, numbers: list(a)): option(a) => None;
}
)();
};
In TestB the compiler complains with
41 │ };
42 │
43 │ module TestB = {
44 │ let x =
. │ ...
50 │ )();
51 │ };
52 │
53 │ module Number = {
The type of this module contains type variables that cannot be generalized:
{ let x: list('_a) => option('_a); }
This happens when the type system senses there's a mutation/side-effect,
in combination with a polymorphic value.
Using or annotating that value usually solves it. More info:
https://realworldocaml.org/v1/en/html/imperative-programming-1.html#side-effects-and-weak-polymorphism
why is that? And how could I approach the problem of hiding y from the user of the module?
P.s.: When reformatting the return type annotation in TestB gets put behind the None like so: (type a, numbers: list(a)) => (None: option(a)). Why here and not in module TestA? As far as I understood it this just "tags" the returned value, so I don't see a difference here?