F# 尾调用因缺少括号而中断

F# tail call broken by lack of parentheses

在与 F# 团队一起测试 F# 尾调用时 blog article 我发现 几乎相同 代码具有相同的结果,但 不同 IL 尽管代码中只有括号不同。

下一个代码由编译器优化,我在 IL 的末尾看到 br.s IL_0000,没有调用 sumSoFar

let rec loopAndSum aList sumSoFar = 
    match aList with
    | [] -> sumSoFar
    | x :: xs -> 
        loopAndSum xs (sumSoFar + x)

loopAndSum [ 1..5 ] 0 
|> printfn "sum: %i"

但是那部分没有被编译器优化,它有 call bla_bla.loopAndSum 接近 IL 的末尾。

let rec loopAndSum aList sumSoFar = 
    match aList with
    | [] -> sumSoFar
    | x :: xs -> 
        loopAndSum xs sumSoFar + x

loopAndSum [ 1..5 ] 0 
|> printfn "sum: %i"

这些示例的不同之处仅在于 sumSoFar + x 周围的括号。 你可以玩它并在 .NET Fiddle.

查看 IL

有人知道为什么括号很重要吗?

函数应用程序的优先级高于任何运算符。所以没有括号,它相当于:

(loopAndSum xs sumSoFar) + x

因此不是尾调用:加法是在递归调用之后进行的。结果值正确纯属偶然