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
因此不是尾调用:加法是在递归调用之后进行的。结果值正确纯属偶然
在与 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.
有人知道为什么括号很重要吗?
函数应用程序的优先级高于任何运算符。所以没有括号,它相当于:
(loopAndSum xs sumSoFar) + x
因此不是尾调用:加法是在递归调用之后进行的。结果值正确纯属偶然