0

While testing F# tail calls with F# team blog article I found that almost the same code has the same result but different IL although only parentheses in the code differ.

Next code is optimized by compiler and I see br.s IL_0000 in the end of IL and no calls to sumSoFar

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

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

But that piece is not optimized by compiler and it has call bla_bla.loopAndSum near to the end of IL.

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

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

These examples differ only with parentheses around sumSoFar + x. You can play with it and look at IL at .NET Fiddle.

Does anybody know why parentheses matter?

Roman Dibikhin
  • 856
  • 4
  • 15

1 Answers1

4

Function application has higher precedence than any operator. So without the parentheses, it is equivalent to:

(loopAndSum xs sumSoFar) + x

Therefore it is not a tail call: the addition is performed after the recursive call. It is just by chance that the result value is correct.

Tarmil
  • 11,177
  • 30
  • 35
  • thank you for clarification. Could you point at spec where it's described? – Roman Dibikhin Mar 08 '15 at 08:55
  • At the bottom of [this page](https://msdn.microsoft.com/en-us/library/dd233228.aspx) there is an operator precedence table, function application is near the bottom between `**` and pattern matching. – Tarmil Mar 08 '15 at 11:40