I coded 3 factorial algorithms:
- First, I expect to fail by Stack Overflow. No problem.
- Second, I try tail recusive call, convert previous algorithm from recursive to iterative. It doesn't work but I don't understand why.
- Third, I use
trampoline()
method and works fine as I expect.
def factorial
factorial = { BigInteger n ->
if (n == 1) return 1
n * factorial(n - 1)
}
factorial(1000) // Stack Overflow
factorial = { Integer n, BigInteger acc = 1 ->
if (n == 1) return acc
factorial(n - 1, n * acc)
}
factorial(1000) // Stack Overflow, why???
factorial = { Integer n, BigInteger acc = 1 ->
if (n == 1) return acc
factorial.trampoline(n - 1, n * acc)
}.trampoline()
factorial(1000) // It works
Starting with version 2.3 Groovy supports tail recursion with the @TailRecursive annotation for methods: http://java.dzone.com/articles/groovy-goodness-more-efficient
There is no tail recursion in Java, and hence there is none in Groovy either (without using something liketrampoline()
as you have shown)The closest I have seen to this, is an AST transformation which cleverly wraps the return recursion into a while loop
Edit
You're right, Java (and hence Groovy) do support this sort of tail-call iteration, however, it doesn't seem to work with Closures...
This code however (using a method rather than a closure for the
fact
call):When saved as
Test.groovy
and executed withgroovy Test.groovy
runs, and prints the answer:As a guess, I would say that the JVM does not know how to optimise closures (like it does with methods), so this tail call does not get optimised out in the bytecode before it is executed