Tail Recursion
(defun last (L)
(if (not (cdr L))
(car L)
(last (cdr L))))
(defun gcd (n m)
(cond ((= n m) n) ;a
((= n 0) m) ;b
((= m 0) n) ;c
((> n m)
(gcd (- n m) m)) ;d
(t (gcd n (- m n))))) ;e
Tail Recursion Transformation
Example - Last
(defun last (L)
(while (cdr L)
(setq L (cdr L)))
(car L))
Example - gcd
(defun gcd (n m)
(while (and (/= n m) (/= n 0) (/= m 0))
(if (> n m)
(setq n (- n m))
(setq m (- m n))))
(cond ((= n m) n)
((= n 0) m)
((= m 0) n)))
Recursive Binary Search
(defun binary-search (A first last val)
(if (> first last) -1
(let ((mid (/ (+ first last) 2)))
(cond
((= (elt A mid) val) mid)
((> (elt A mid) val)
(binary-search A first
(- mid 1) val))
(t (binary-search A (+ mid 1)
last val))))))
(binary-search a 0 4 2); 1
(binary-search a 0 4 7) ; -1
Result of the Transformation
(defun binary-search-it (A first last val)
(let ((mid (/ (+ first last) 2)))
(while (and (<= first last)
(not (= (elt A mid) val)))
(if (> (elt A mid) val)
(setq last (- mid 1))
(setq first (+ mid 1)))
(setq mid (/ (+ first last)
2)))
(if (= (elt A mid) val) mid -1)))
(binary-search-it a 0 4 2) ; 1
(binary-search-it a 0 4 7) ; -1
Counter Example
(defun factorial (n)
(if (< n 2) 1
(* n (factorial (- n 1)))))
It's not a tail recursive function because the result of the function
call must be multiplied afterwards with n.
Converting to Tail-Recursive
Tail-Recursive Factorial
(defun fact (n result)
(if (< n 2)
result
(fact (- n 1) (* n result))))
(fact 6 1) ; => 720
Recursive Fibonacci
Usual recursive implementation: non tail recursive because the results
of two recursive calls must be added to obtain the result.
(defun fib1 (n)
(if (< n 2)
1
(+ (fib1 (- n 1)) (fib1 (- n 2)))))
(fib1 4) ; => 5
Transformed into a tail-recursive function:
(defun fib2 (n f1 f2)
(if (< n 2)
f1
(fib2 (- n 1) (+ f1 f2) f1)))
(fib2 5 1 1) ; => 8
Simple Transformation for Functions with a Single Recursive Call
Top-Down Transformation
When there's only one recursive call involved in a computation
(factorial), and when the computation is a simple associative
operation (+, *) -> store the value in a local variable.
(defun factorial (n)
(let ((f 1))
(while (>= n 2)
(setq f (* f n))
(setq n (- n 1)))
f))
Bottom-Up Transformation
Starting from the base case going up. A local variable (f) stands in
place of the value returned by recursive calls.
(defun factorial (n)
(let ((f 1) (i 2))
(while (<= i n)
(setq f (* f i) i (+ i 1)))
f))
One Recursive Call
(defun factorial1 (n)
(let ((st ()) (r 1) (ln n))
(push ln st)
(while st
(cond
((>= ln 2)
(setq ln (- ln 1))
(push ln 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 BU Version
(defun iter-f (n)
(let ((f 2) (i 2))
(while (<= i n)
(setq f (+ (* 2 i i)
(* 3 f)))
(setq i (+ i 1)))
f))
Iterative Version
(defun f (n)
(let ((st ()) (r 2) (ln 0))
(push n st)
(while st
(cond
((> n 1)
(setq n (- n 1))
(push n st))
(t (setq ln (pop st))
(setq r (+ (* 2 ln ln)
(* 3 r))))))
r))