Programming Recursion

2012  With Rz language (version 3.3)

This is a small introduction to recursive programming.  You need to read to think along with this essay. 
Recursion needs:
1)  terminating case
2)  recursive case with increasing/decreasing parameter(s)

Most important thing is choosing the parameters.

1. Simple recursion, follow a recursive definition. For example,

factorial(n)
  if n == 0 return 1
  else return n * factorial(n-1)

written in NUT as

factorial(n){
  if( n == 0 ) return 1;
  else return n * factorial(n-1);
}

2. summation from n to m

using n as increasing parameter and check its termination with m.
the recursive case is n + sum(n+1, m).

sum(n, m){
  if( n == m ) return m;
  else return n + sum( n+1, m);
}

3. We can also use an "accumulating parameter" to hold the intermediate result.  This can turn a recursion into a special from called "tail-recursion".

using p to hold the intermediate result

sum2(n, m, p){
  if( n == m ) return n+p;
  else return sum2( n+1, m, n+p );
}

it is called with p starts at 0.
The "tail-recursion" is more efficient than a general recursion form because the last recursive call can be turned into a "goto-beginning" hence saving a function call (and stack space).  This makes recursion as fast as a loop. (This tail-call can be detected and exploited by any modern compiler).

4.  Now we can try another problem.  Doing multiplication by repeat addition.  n * m  can be calculated by n + n + ...  m times.

mul(n, m){
  if( m == 1 ) return n;
  else return n + mul( n, m-1 );
}

The recursion will go on for m times.  

5.  We can do better by rearranging the recurrence definition.  If we do grouping (n + n) = 2n  and
2n + 2n + ..  It will need only m/2 times.  We repeat doing this:
4n + 4n + ....   m/4 times.
...
mn  ...          m/m  or 1 times.

The n * m  will need only log_2 m times of loop.  This is much faster.
using p to hold the intermediate result.

mul2(n, m, p){
  if( m == 1 ) return p;
  else return mul2( n+n, m/2, n+p);
}

  Every time we recurse, n is double, m is half.  Start with the call   mul2(n,m,n)
The mul2 is faster than mul by logarithmic order. This shows that improving the "algorithm" can yield very large gain.

Exercises  (to try out your brain)

1.  Here is the "strcpy" function.  A string is an array of character (integer) terminated with a zero.

strcpy(s1 s2){    // copy from s2 to s1
  i = 0;
  while( s2[i] > 0 ){
    s1[i] = s2[i];
    i = i + 1;
  }
  s1[i] = 0;      // terminate with 0
}

Write a recursive version of it.

2.  Write a recursive function to reverse a string.
3.  Do you know a Fibonacci number.  A simple implementation will be very inefficient.  Write a recursive function using an accumalating parameter will turn that into a very efficient program.
4.  The fun bit of recursion is when you use it to "build" a list.  It is very elegant.  Think how you can write an "append" function using recursion.  It is beautiful.

Prabhas Chongstitvatana
last update 5 June 2012