Dana Vrajitoru
C311 Programming Languages

General Transformation of Recursive Functions

General Transformation

Transformation

One Recursive Call
The stack stores the values of n. The variable r stores the result of the recursive function call.

(defun factorial1 (n)
  (let ((st ()) (r 1))
    (push n st)
    (while st
      (cond
       ((>= n 2)
        (setq n (- n 1))
        (push n st))
       (t (setq r (* r (pop st))))))
    r))

Second Example

f(n) = 2 n2 + 3 f(n-1), 	f(1) = 2

(defun f (n)
  (if (= n 1) 2
    (+ (* 2 n n)
       (* 3 (f (- n 1))))))

Iterative Version
Just like before, the stack stores n, while r is the result of the recursive call. Once we reach the base case and we start coming back up, we need a local variable to store the copy of n as we pop it from the stack, because the test for having reached the base case depends on it.

(defun f (n)
  (let ((st ()) (r 2) (ln 0))
    (push n st)
    (while st
      (cond
       ((> n 2)
        (setq n (- n 1))
        (push n st))
       (t (setq ln (pop st))
          (setq r (+ (* 2 ln ln)
                     (* 3 r))))))
    r))

Labels/States in the General Case
Original Recursive Iterative
RC(n) // L0
{
  ...
  RC(n1); // L1
  instructions1      
  RC(n2); // L2
  ...
}
frame = pop(stack);    
n = frame[0];
label=frame[1];
if (label == L1) {
  instructions1
  push(n, L2);
  push(n2, L0);
}
...

Tree

Tree Structure

(defun root (T) "The root of the tree."
  (if T (car T)))
(defun left-subtree (T) 
  "The left subtree, also a list."
  (if (and T (cdr T))
    (car (cdr T)))) ; (cadr T)
(defun right-subtree (T) 
  "The right subtree, also a list."
  (if (> (length T) 2)
    (car (cdr (cdr T))))) ; (caddr T)

Print in Pre-Order

(defun print-preorder (T)
  "Prints the tree in preorder. Root - L - R"
  (if T
      (progn
        (mapc 'princ (list (root T) " "))
        (print-preorder (left-subtree T))
        (print-preorder (right-subtree T)))))
(setq S '(23 (51 (18) (33 (5))) (7 () (10))))
(print-preorder S)
23 51 18 33 5 7 10 nil

States

Iteration

(defun print-preor (T)
  "Prints the list in preorder without recursion."
  (let ((stackT nil) (frame nil) 
        (state nil))
    (push (cons T 'left) stackT)
    (while stackT
      (setq frame (pop stackT))
      (setq T (car frame) state (cdr frame))
      (if T
          (cond ((eq state 'left)
                 (my-print (root T) " ")
                 (push (cons T 'right) stackT)
                 (push (cons (left-subtree T) 
                             'left) stackT))
                ((eq state 'right)
                 (push (cons (right-subtree T) 
                             'left) stackT)))))))
where the function my-print is defined the following way:
(defun my-print (&rest L)
  (dolist (e L)
    (princ e)))

Optimization

(defun print-preord (T)
  "An optimization of the function above."
  (let ((stackT ()))
    (while T
      (my-print (root T) " ")
      (push T stackT)
      (setq T (left-subtree T)))
    (while stackT
      (setq T (pop stackT))
      (setq T (right-subtree T))
      (while T
        (my-print (root T) " ")
        (push T stackT)
        (setq T (left-subtree T))))))

Example The combinatorial function.

(defun comb (n m)
      (cond 
       ((= n m) 1)
       ((= m 0) 1)
       ((= m 1) n )
       ((= m (- n 1)) n )
       (t (+ (comb (- n 1) m) (comb (- n 1) (- m 1))))))

We need 3 labels: 'left for the state before the first recursive call, 'right for the state before the second recursive call, and 'done for after the second recursive call. We need a state for that third place in the program because there is an addition operation to do after it.

The variable r will contain the result of the most recently completed recursive call. When we move on to the second recursive call, we store the value returned by the first recursive call in the stack frame as the "result" component. This value can be used when we return from the second recursive call to be added to the variable r to obtain the final result of the function when the state is 'done.

(defun comb2 (n m)
  (let ((st ()) (result 0) (r 0))
    (push (list n m 0 'left) st)
    (while st
      (setq frame (pop st))
      (setq n (car frame) m (car (cdr frame)) 
            result (car (cdr (cdr frame)))
            label (car (cdr (cdr (cdr frame)))))
      (cond 
       ((equal label 'done) (setq r (+ r result)))
       ((= n m) (setq r 1))
       ((= m 0) (setq r 1))
       ((= m 1) (setq r n ))
       ((= m (- n 1)) (setq r n ))
       ((equal label 'left)
        (push (list n m 0 'right) st)
        (push (list (- n 1) m 0 'left) st))
       ((equal label 'right)
        (push (list n m r 'done) st)
        (push (list (- n 1) (- m 1) 0 'left) st))
       (t result)))
    r))