**0**

# Can any recursive function be a tail-recursive function?

###
#1
Crossbones+ - Reputation: **6495**

Posted 01 July 2012 - 09:03 PM

External Articulation of Concepts Materializes Innate Knowledge of One's Craft and Science

**Beginner in Game Development? **Read here. And read here.

Super Mario Bros clone tutorial written in XNA 4.0 [MonoGame, ANX, and MonoXNA] by Scott Haley

If you have found any of the posts helpful, please show your appreciation by clicking the up arrow on those posts

###
#2
Moderators - Reputation: **11318**

Posted 01 July 2012 - 10:11 PM

###
#3
Members - Reputation: **1478**

Posted 02 July 2012 - 12:17 AM

int fib(int n) { if (n < 2) return n; else return fib(n-1) + fib(n-2); }

Note that the last operation is the addition of the results of the recursive calls, there are no tail calls to optimize.

openwar - the real-time tactical war-game platform

###
#4
Crossbones+ - Reputation: **2466**

Posted 02 July 2012 - 12:31 AM

Using an explicit stack and tacking on some unrelated meaningless tail-recursion does not count as converting the algorithm to a tail-recursive implementation.

My website dedicated to sorting algorithms

###
#5
Members - Reputation: **1054**

Posted 03 July 2012 - 02:55 AM

If your writing a function and it absolutely has to be done recursively for whatever reason (there are a few instances where recursion is handy) and it can be made as a tail-recursive function then do it.

When we did recursion in computer science it took one of the school computers 45 minutes to solve the Fibonacci sequence for n = 40 written in VB.net on .net version 4. Impossible to time the iterative approach with what we had available.

###
#6
Crossbones+ - Reputation: **11901**

Posted 03 July 2012 - 03:27 AM

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.

###
#7
Crossbones+ - Reputation: **19082**

Posted 03 July 2012 - 03:32 AM

Here is a very fast implementation of Fibonacci numbers using recursion:

#include <iostream> // M represents a matrix of the form // (a b ) // (b a+b) struct M { long a, b; M(long a, long b) : a(a), b(b) { } }; M operator*(M x, M y) { return M(x.a*y.a + x.b*y.b, x.a*y.b + x.b*y.a + x.b*y.b); } // Fast exponentiation M pow(M x, unsigned n) { if (n==0) return M(1,0); if (n==1) return x; if (n%2==0) return pow(x*x,n/2); if (n%3==0) return pow(x*x*x,n/3); return x*pow(x,n-1); } // Compute // (0 1)^n = (fib(n-1) fib(n) ) // (1 1) ( fib(n) fib(n+1)) long fib(unsigned n) { M m = pow(M(0,1),n); return m.b; } int main() { std::cout << fib(40) << '\n'; }

Depth-first search is the standard example that should come to mind instead. A recursive implementation is in this case the most natural, it's perfectly fast and small variations of it can be used for many purposes (e.g., to enumerate possibilities in many combinatorial problems, or to play chess).

**Edited by alvaro, 03 July 2012 - 11:21 AM.**

###
#8
Moderators - Reputation: **11318**

Posted 03 July 2012 - 06:44 AM

By that logic, there's "no use for recursion" in tail recursive functions at all and hence no point to the idea of tail recursion, because an existing tail recursive function can be trivially transformed into an iterative form as well. Just update the parameter variables and jump to the beginning of the function body, and you have your iterative version. However, not all languages are the same in terms of control structures, and iteration is non-idiomatic in many, if not most, functional languages. In those languages a tail recursive transformation has the same process and the same point as a manual transformation to an iterative version in an imperative language. In other words, a completely pointless waste of programmer time and computing resources in the ordinary case, but useful once in a while. Ultimately, they all express same algorithm, the difference is in the control structures used to implement that algorithm: regular recursion, tail recursion or iteration. Whether or not the change of expression of an algorithm represents a different "function" is a semantic argument.Anything can be rewritten an infinite number of ways, but in the purest sense, no not every recursive function can be rewritten tail-recursive instead. If it could then via a straightforward transformation we could change those functions to use iteration (which is generally more efficient) and have no use for recursion any more.

Using an explicit stack and tacking on some unrelated meaningless tail-recursion does not count as converting the algorithm to a tail-recursive implementation.

Incorrect. Fibonacci can be written tail recursively. There's just no point to writing the naive implementation tail recursively because it requires explicitly duplicating the stack structure that the recursive calls automatically generate, and this implicit stack is almost always faster than any explicit stack structure. Any recursive algorithm can be written to use an explicit stack in place of an implicit stack of function calls. This includes Fibonacci, tree-traversal, searches, sorts or whatever recursive algorithm you can imagine. You push data on an explicitly managed stack that would normally be passed as parameters in a recursive call and then pop the stack as computations progress. Again, this is the same process that you would use to transform a recursive function into an iterative version of the same function. The only difference that instead of a loop operating on the explicit stack you use a tail recursive call on the explicit stack.Fibonacci cannot be written tail recursively as said, Some sorting algorithms that are written recursively I believe can't be tail recursive either.

And that's just for a naive transformation. Actual examination of the algorithm can result in more sophisticated transformations. As an example, Dijkstra's algorithm in a tail-recursive Scheme implementation, which is essentially the same as alvaro's algorithm minus the special case for exponentiation of powers of three:

(define (fib n) (define (fib-aux a b p q count) (cond ((= count 0) b) ((even? count) (fib-aux a b (+ (* p p) (* q q)) (+ (* q q) (* 2 p q)) (/ count 2))) (else (fib-aux (+ (* b q) (* a q) (* a p)) (+ (* b p) (* a q)) p q (- count 1))))) (fib-aux 1 0 0 1 n))