Reputation: 3105
I would like to know if this is a bug or if I am doing something wrong. I am running F# in mono/linux, the following code crashes giving me a stack overflow without any stack trace.
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
this works fine when I run the same code in the REPL.
Interestingly enough this works fine
let rec gcd a b =
match b with
| x when x = 0 -> a
| _ -> gcd b (a%b)
printfn "%A" (gcd 12 3)
EDIT:
Trying the --optimize solution doesn't help, interestingly I found that following John Palmer's advice and replacing x when x = 0
with just 0
worked, however when trying the same technique with int64
, 0L
again gives me the same stack overflow. I don't see how this is a tail optimization problem since 3 is a factor of 12 the stack depth is low. I am putting this down as a bug unless someone else can enlighten me what is happening here.
Upvotes: 2
Views: 79
Reputation: 25516
In general, the fsi often is set up to use --optimize
(definitely on windows from within Visual Studio, not sure about on mono).
As a result, the REPL will apply tail calls, but an unoptimized compiled app won't. You can probably fix this by compiling with fsharpc --optimize+ ...
also, change
|x when x = 0
to
|0
EDIT: I think this might actually be a compiler / mono bug - adding a printf anywhere gets rid of it.
Decompiled versions:
bug:
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
and good:
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
Nothing that seems weird to me.
I am running mono 3.2.8 and a reasonably modern F# compiler - I will test on latest git when I have time to recompile the compiler.
Upvotes: 3