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

时间:2014-06-16 11:55:39

标签: 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工作,但是当尝试相同的技术时使用int640L再次给我相同的堆栈溢出。我不知道这是一个尾部优化问题,因为3是堆栈深度低的12倍。除非别人可以告诉我这里发生了什么,否则我把它作为一个错误。

1 个答案:

答案 0 :(得分:3)

一般情况下,fsi通常设置为使用--optimize(在Visual Studio中的Windows上,不确定单声道)。

因此,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。