In F# I have a very long code file like
let rec f1 a1 a2 a3 a4 a5 .. aN =
...
and f2 a1 a2 a3 a4 a5 ... aN =
...
and f3 a1 a2 a3 a4 a5 ... aN =
...
and f40 a1 a2 a3 a4 a5 ... aN =
...
In other words there are many mutually recursive functions, each with a lot of parameters.
Now the problem is that the file is 17000 lines long, and Visual Studio has become too slow. (For example, I can't hover the mouse over an item to see its type; if I press the dot, there is no completion, and so on)
Therefore I need to split the file into many smaller files. But I can't see a mechanical and easy way to do it.
Could you please give me an advice? I would like a mechanical way to split the code into multiple files, which does not involve writing the type of all functions (preserve type inference).
In the meantime I found a solution (tested):
This is the initial situation (simplified to only have four functions, but in reality they are many more):
let rec f1 a b c =
f2 a b c;
f3 a b c;
f4 a b c;
and f2 a b c =
f1 a b c;
f3 a b c
f4 a b c
and f3 a b c =
f1 a b c;
f2 a b c
f4 a b c
and f4 a b c =
f1 a b c;
f2 a b c
f3 a b c
And here is the solution:
Suppose you decide to move f3 to another file. Then you can split the file above in two files as follows:
FILE 1
======
let callRef mf =
match !mf with
| None -> failwith "function ref is none"
| Some f -> f
let r_f3 = ref None;
let rec f1 a1 a2 a3 =
f2 a b c;
callRef r_f3 a1 b1 c1;
f4 a1 b1 c1;
and f2 a1 a2 a3 =
f1 a b c;
callRef r_f3 a1 b1 c1;
f4 a1 b1 c1;
and f4 a1 a2 a3 =
f1 a b c;
f2 a1 b1 c1;
callRef r_f3 a1 b1 c1;
FILE 2
======
let f3 a1 a2 a3 =
f1 a b c;
f2 a1 b1 c1;
f4 an bn cn;
Then, in the main initialization function (which is in a third file), you need to do
r_f3 := Some f3;
And that's it.
Repeat the same strategy to move f1, f2 and f4 out of the first file.
Update: This solution works well for functions which return unit, but unfortunately for functions which return an actual type it forces you to specify the function type explicitely, e.g.
let (r_f3 : (t1 -> t2 -> t3 -> t4 -> t5) option ref) = ref None;
or you can do this:
let (r_f3 : 'a option ref) = ref None;
but you'll get a compiler warning.