20-CS-4003-001 | Organization of Programming Languages | Fall 2018 |
---|---|---|
Tail Recursion |
Tail Recursion Example
(define findmax ;; Non-tail recursive (lambda (lst) (if (null? lst) '() (if (null? (cdr lst)) (car lst) (max (car lst) (findmax (cdr lst))))))) (define test1 (let ((lst '(4 5 6 1 2 31 9 10 22 11 5 7))) (findmax lst))) (define findmax_acc ;; Tail recursive - invariant: (lambda (lst acc) ;; acc is largest number seen (if (null? lst) ;; prior to elements of lst acc ;; All have been seen, invariant (findmax_acc (cdr lst) ;; implies solution (max (car lst) acc))))) (define test2 (let ((lst '(4 5 6 1 2 31 9 10 22 11 5 7))) (findmax_acc (cdr lst) (car lst)))) | - | The function findmax is not tail recursive since control must return from the recursive call to findmax to complete the max invocation. The function findmax_acc is tail recursive: an accumulator acc is used to advance execution state to the next recursive call so that nothing has to be placed on the stack. This state variable enables one to state a proposition that applies at every recursive call and, when execution completes, implies correctness of the function. Such a proposition is called an invariant. In the case of findmax_acc the invariant is the value of acc is equal to the greatest number seen prior to the elements of the list lst. This invariant holds on every call because the new value of acc is (max (car lst) acc) which obviously implies the invariant holds on the next recursive call if it holds on the current one. When lst is empty all numbers have been seen so the invariant implies that the value of acc is equal to the greatest number in the given input list and that is why acc is returned when lst is empty. |