我想知道这是一个错误还是我做错了什么。我在 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/