使用相互递归函数拆分巨大的 F# 文件
Split huge F# file with mutually recursive functions
在 F# 中,我有一个很长的代码文件,例如
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 =
...
换句话说,有很多相互递归的函数,每个函数都有很多参数。
现在的问题是文件有 17000 行长,Visual Studio 变得太慢了。 (例如,我无法将鼠标悬停在项目上以查看其类型;如果我按下点,则没有完成,等等)
因此我需要将文件拆分成许多较小的文件。但是我看不到一个机械和简单的方法来做到这一点。
你能给我一个建议吗?我想要一种机械的方式将代码拆分成多个文件,这不涉及编写所有函数的类型(保留类型推断)。
同时我找到了解决方案(已测试):
这是初始情况(简化为只有四个功能,但实际上它们更多):
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
这里是解决方案:
假设您决定将 f3 移动到另一个文件。然后你可以将上面的文件分成两个文件如下:
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;
然后,在主初始化函数中(在第三个文件中),你需要做
r_f3 := Some f3;
就是这样。
重复相同的策略将 f1、f2 和 f4 移出第一个文件。
更新: 此解决方案适用于 return 单元的函数,但不幸的是,对于 return 实际类型的函数,它会强制您指定函数类型明确,例如
let (r_f3 : (t1 -> t2 -> t3 -> t4 -> t5) option ref) = ref None;
或者您可以这样做:
let (r_f3 : 'a option ref) = ref None;
但是您会收到编译器警告。
在 F# 中,我有一个很长的代码文件,例如
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 =
...
换句话说,有很多相互递归的函数,每个函数都有很多参数。
现在的问题是文件有 17000 行长,Visual Studio 变得太慢了。 (例如,我无法将鼠标悬停在项目上以查看其类型;如果我按下点,则没有完成,等等)
因此我需要将文件拆分成许多较小的文件。但是我看不到一个机械和简单的方法来做到这一点。
你能给我一个建议吗?我想要一种机械的方式将代码拆分成多个文件,这不涉及编写所有函数的类型(保留类型推断)。
同时我找到了解决方案(已测试):
这是初始情况(简化为只有四个功能,但实际上它们更多):
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
这里是解决方案:
假设您决定将 f3 移动到另一个文件。然后你可以将上面的文件分成两个文件如下:
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;
然后,在主初始化函数中(在第三个文件中),你需要做
r_f3 := Some f3;
就是这样。
重复相同的策略将 f1、f2 和 f4 移出第一个文件。
更新: 此解决方案适用于 return 单元的函数,但不幸的是,对于 return 实际类型的函数,它会强制您指定函数类型明确,例如
let (r_f3 : (t1 -> t2 -> t3 -> t4 -> t5) option ref) = ref None;
或者您可以这样做:
let (r_f3 : 'a option ref) = ref None;
但是您会收到编译器警告。