linux - F# 代码在 REPL 中工作正常,但在编译期间出现堆栈溢出

标签 linux f# mono stack-overflow

我想知道这是一个错误还是我做错了什么。我在 mono/linux 中运行 F#,以下代码崩溃,导致堆栈溢出,没有任何堆栈跟踪。

let rec gcd a b =
    match b with
       | x when x = 0 -> a
       | _ -> gcd b (a%b)

let z = (gcd 12 3)

printfn "%A" z

当我在 REPL 中运行相同的代码时,效果很好。

有趣的是,这工作得很好

let rec gcd a b =
    match b with
       | x when x = 0 -> a
       | _ -> gcd b (a%b)

printfn "%A" (gcd 12 3)

编辑:

尝试 --optimize 解决方案并没有帮助,有趣的是,我发现遵循 John Palmer 的建议并将 x when x = 0 替换为 0 有效,但是当使用 int64 尝试相同的技术,0L 再次出现相同的堆栈溢出。我不明白这是一个尾部优化问题,因为 3 是 12 的因数,堆栈深度很低。我将其视为一个错误,除非其他人可以告诉我这里发生了什么。

最佳答案

一般来说,fsi 通常设置为使用 --optimize(肯定是在 Visual Studio 中的 Windows 上,不确定在 Mono 上是否如此)。

因此,REPL 将应用尾部调用,但未优化的编译应用程序不会。您可以通过使用 fsharpc --optimize+ ...

进行编译来解决此问题

还有,改变

|x when x = 0

|0

编辑:我认为这实际上可能是一个编译器/单声道错误 - 在任何地方添加 printf 就可以摆脱它。

反编译版本:

错误:

IL_0000:  ldarg.1 
IL_0001:  brtrue.s IL_0005
IL_0003:  ldarg.0 
IL_0004:  ret 
IL_0005:  ldarg.1 
IL_0006:  ldarg.0 
IL_0007:  ldarg.1 
IL_0008:  rem 
IL_0009:  starg.s 1
IL_000b:  starg.s 0
IL_000d:  br.s IL_0000

很好:

IL_0000:  ldarg.1 
IL_0001:  switch (
  IL_0014)
IL_000a:  ldarg.1 
IL_000b:  ldarg.0 
IL_000c:  ldarg.1 
IL_000d:  rem 
IL_000e:  starg.s 1
IL_0010:  starg.s 0
IL_0012:  br.s IL_0000

IL_0014:  ldarg.0 
IL_0015:  ret 

我觉得没什么奇怪的。

我正在运行 mono 3.2.8 和一个相当现代的 F# 编译器 - 当我有时间重新编译编译器时,我将在最新的 git 上进行测试。

关于linux - F# 代码在 REPL 中工作正常,但在编译期间出现堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24243173/

相关文章:

f# - 我可以以某种方式在单个文件中组织方法定义顺序吗?

python - 将标准输出重定向到文件显示错误内容

计算 C 中两个 ISO 8601 日期(包括毫秒)之间的差异

f# - 在 F# Interactive 中获取类型的描述?

f# - 有没有办法使用 fslex/Lexing.LexBuffer 执行前瞻

wcf - 在 Mono 上托管 WCF 的问题

c# - C# 中的加密是单声道跨平台吗?

.net - 在 Linux/Ubuntu 上大规模部署 .net mono 应用程序

linux - 如何同时接受 TCP 连接 <ip :port> in many threads?

java - 为什么 Maven 在 lib 目录中寻找一个 Artifact 而不是我正在运行它的 Artifact ?