Category:Recursion: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
(Removed extra sentence and added an example of a non-tail-recursive function becoming tail-recursive)
Line 10: Line 10:
More than one end condition is allowed. More than one recursion condition is allowed.
More than one end condition is allowed. More than one recursion condition is allowed.


Many recursion problems can be solved with an iterative method, or using a [[loop]] of some sort (usually recursion and iteration are contrasted in programming, even though recursion is a specific type of iteration). In some languages, the factorial example is best done with a loop because of function call overhead. Some other languages, like [[Scheme]], are designed to favor recursion over explicit looping, using tail recursion optimization to convert recursive calls into loop structures. If loop structures are not available in your language (or not allowed by the rules of your task), recursion is a good way to go.
Many recursion problems can be solved with an iterative method, or using a [[loop]] of some sort (usually recursion and iteration are contrasted in programming, even though recursion is a specific type of iteration). In some languages, the factorial example is best done with a loop because of function call overhead. Some other languages, like [[Scheme]], are designed to favor recursion over explicit looping, using tail recursion optimization to convert recursive calls into loop structures.


'''Tail recursion''' is a specific type of recursion where the recursion call is the last call in the function. Because tail recursive functions can easily and automatically be transformed into a normal [[:Category:Iteration|iterative]] functions, tail recursion is used in languages like Scheme or [[OCaml]] to optimize function calls, while still keeping the function definitions small and easy to read. The actual optimization transforms recursive calls into simple branches (or jumps) with logic to change the arguments for the next run through the function.
'''Tail recursion''' is a specific type of recursion where the recursion call is the last call in the function. Because tail recursive functions can easily and automatically be transformed into a normal [[:Category:Iteration|iterative]] functions, tail recursion is used in languages like Scheme or [[OCaml]] to optimize function calls, while still keeping the function definitions small and easy to read. The actual optimization transforms recursive calls into simple branches (or jumps) with logic to change the arguments for the next run through the function.
Line 19: Line 19:


Time is saved because each function return takes a long time relative to a simple branch. This benefit is usually not noticed unless function calls are made that would result in large and/or complex call trees. For example, the time difference between iterative and recursive calls of <tt>fibonacci(2)</tt> would probably be minimal (if there is a difference at all), but the time difference for the call <tt>fibonacci(40)</tt> would probably be drastic.
Time is saved because each function return takes a long time relative to a simple branch. This benefit is usually not noticed unless function calls are made that would result in large and/or complex call trees. For example, the time difference between iterative and recursive calls of <tt>fibonacci(2)</tt> would probably be minimal (if there is a difference at all), but the time difference for the call <tt>fibonacci(40)</tt> would probably be drastic.

Sometimes, tail-recursive functions are coded in a way that makes the function not tail-recursive. The example above could become tail recursive if it were transformed to look like this:
<pre>function F with arguments
if end condition is met
return end condition value
else
return F called with new set of arguments</pre>


Below is a list of examples of recursion in computing.
Below is a list of examples of recursion in computing.

Revision as of 16:55, 5 December 2008

Recursion is the idea that a function can come to an answer by repeatedly calling itself with new arguments until a "base case" or "end condition" is met. One good example is a factorial function. The base case for factorial is "0!" (some people like to use 1 or 2, but 0 is OK for instructional purposes). When 5 is sent as an argument to a recursive factorial function, the function does not know the answer right away. All it knows is that 5! = 5 * 4!. So it calls itself to find out what 4! is. This process continues until it gets to 0!, which is 1. Now it has built up a train of answers: 5! = 5 * 4! = 5 * 4 * 3! etc., and it can find the final answer. Other common examples include tree traversal and the min/max algorithm.

A pseudocode function to demonstrate recursion would look something like this:

function F with arguments
    if end condition is not met
      return F called with new set of arguments
    else
      return end condition value

More than one end condition is allowed. More than one recursion condition is allowed.

Many recursion problems can be solved with an iterative method, or using a loop of some sort (usually recursion and iteration are contrasted in programming, even though recursion is a specific type of iteration). In some languages, the factorial example is best done with a loop because of function call overhead. Some other languages, like Scheme, are designed to favor recursion over explicit looping, using tail recursion optimization to convert recursive calls into loop structures.

Tail recursion is a specific type of recursion where the recursion call is the last call in the function. Because tail recursive functions can easily and automatically be transformed into a normal iterative functions, tail recursion is used in languages like Scheme or OCaml to optimize function calls, while still keeping the function definitions small and easy to read. The actual optimization transforms recursive calls into simple branches (or jumps) with logic to change the arguments for the next run through the function.

The benefits of this optimization are primarily stack related. Transforming recursive functions into iterative functions can save memory and time.

Memory is saved by reducing an entire call stack into one function call. This way, more complex calls can be evaluated without running out of memory.

Time is saved because each function return takes a long time relative to a simple branch. This benefit is usually not noticed unless function calls are made that would result in large and/or complex call trees. For example, the time difference between iterative and recursive calls of fibonacci(2) would probably be minimal (if there is a difference at all), but the time difference for the call fibonacci(40) would probably be drastic.

Sometimes, tail-recursive functions are coded in a way that makes the function not tail-recursive. The example above could become tail recursive if it were transformed to look like this:

function F with arguments
    if end condition is met
      return end condition value
    else
      return F called with new set of arguments

Below is a list of examples of recursion in computing.