Programming Recursion

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

(def factorial n ()
  (if (= n 0) 1
     (* 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).

(def sum (n m) ()
  (if (= n m) m
    (+ n (sum (+ n 1) m))))

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

using p to hold the intermediate result

(def sum2 (n m p) ()
  (if (= n m) p
    (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.

(def mul (n m) ()
  (if (= m 1) n
    (+ 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.

(def mul2 (n m p) ()
  (if (= m 1) p
    (mul2 (+ n n) (/ m 2) (+ n p))))

Everytime we recurse, n is double, m is half.
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.

(def strcpy (s1 s2) (i)
  (do
  (set i 0)
  (while (neq (vec s2 i) 0)
    (do
    (setv s1 i (vec s2 i))
    (set i (+ i 1))))
  (setv s1 i 0)))                 // terminate s1 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 8 June 2010