継続渡しスタイルのフィボナッチ関数の次の F# 定義を見てきましたが、これは常に末尾再帰的であると想定していました。
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
Scala で同等のコードを試してみたときに、既存の @tailrec を使用しましたが、Scala コンパイラーが再帰呼び出しが末尾位置にないことを通知したとき、不意を突かれました。
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 })
}
私の Scala 実装は F# のものと同等だと思うので、なぜ関数が末尾再帰的でないのか疑問に思っています。