I've seen around the following F# definition of a continuation-passing-style fibonacci function, that I always assumed to be tail recursive:
let fib k =
let rec fib' k cont =
match k with
| 0 | 1 -> cont 1
| k -> fib' (k-1) (fun a -> fib' (k-2) (fun b -> cont (a+b)))
fib' k id
When trying out the equivalent code in Scala, I've made use of the existent @tailrec and was caught off-guard when the Scala compiler informed me the recursive calls are NOT in tail position:
def fib(k: Int): Int = {
@tailrec def go(k: Int, cont: Int => Int): Int = {
if (k == 0 || k == 1) cont(1)
else go(k-1, { a => go(k-2, { b => cont(a+b) })})
}
go(k, { x => x })
}
I believe my Scala implementation is equivalent to the F# one, so I'm left wondering why the function is not tail recursive?
The second call to
go
on line 4 is not in tail position, it is wrapped inside an anonymous function. (It is in tail position for that function, but not forgo
itself.)For continuation passing style you need Proper Tail Calls, which Scala unfortunately doesn't have. (In order to provide PTCs on the JVM, you need to manage your own stack and not use the JVM call stack which breaks interoperability with other languages, however, interoperability is a major design goal of Scala.)