# Class 41: Tail Recursion (1)

Back to Discussion of Exam 2. On to Tail Recursion (2).

Held: Monday, 14 April 2003

Summary: Today we revisit recursion and consider a more efficient way to write recursive procedures. This technique is called tail recursion.

Related Pages:

Notes:

• Are there questions on the project?
• What did you think about meeting in Saints' Rest?

Overview:

• Kinds of recursion.
• Why do tail recursion.
• Generating lists tail-recursively.
• Lab: Tail Recursion.

## Two Kinds of Recursion

• We've seen (at least) two kinds of shallow recursion in Scheme.
• Recursion in which you do something with the recursive result.
• E.g., definition of `add-to-all`, `factorial`, traditional right-associative `sum`.
• Recursion in which you simply return the recursive result, unchanged.
• E.g., `member?`, the left-associative `sum`.
• The latter kind of recursion is called tail recursion and, in Scheme, is likely to be faster. Why?
• Let's look at the two versions of `sum` (in class).
• Version 1, right associative, not tail recursive.
```(define sumr
(lambda (values)
(if (null? values) 0
(+ (car values) (sumr (cdr values))))))
```
```  + Version 2, left associative, tail recursive.
(define suml
(lambda (values)
(letrec ((suml-helper
(lambda (remaining-values partial-sum)
(if (null? remaining-values) partial-sum
(suml-helper (cdr remaining-values)
(+ partial-sum
(car remaining-values)))))))
(suml-helper values 0))))
```
• Let's sum the list `(1 2 3 4)` and see if one seems to be easier to deal with.
• Right associative
```(sumr (1 2 3 4))
--> (+ 1 (sumr (2 3 4)))
--> (+ 1 (+ 2 (sumr (3 4))))
--> (+ 1 (+ 2 (+ 3 (sumr (4)))))
--> (+ 1 (+ 2 (+ 3 (+ 4 (sumr ())))))
--> (+ 1 (+ 2 (+ 3 (+ 4 0))))
--> (+ 1 (+ 2 (+ 3 4)))
--> (+ 1 (+ 2 7))
--> (+ 1 9)
--> 10
```
• Left associative
```(suml (1 2 3 4))
--> (suml-helper (1 2 3 4) 0)
--> (suml-helper (2 3 4) 1)
--> (suml-helper (3 4) 3)
--> (suml-helper (4) 6)
--> (suml-helper () 10)
--> 10
```
• Which would you prefer to evaluate by hand?
• In the right-associative case, Scheme needs to remember the things to do once the recursion reaches the base case.
• Remembering that stuff takes extra memory and time.
• Hence, tail-recursive procedures are normally quicker than non-tail-recursive procedures.
• We can also use named lets for tail-recursive procedures.

## Making Procedures Tail Recursive

• The normal strategy for making procedures tail recursive is the one we used for `suml`:
• Make a helper procedure with one additional parameter.
• The additional parameter accumulates partial solutions. Hence, we often call it an accumulator.
• You can often transform a non-tail-recursive (but recursive) procedure in to a tail-recursive procedure:
• Build that helper with an extra parameter.
• The accumulator normally starts out with the value from the old base case (the one in the non-tail-recursive procedure).
• The operation used to update the accumulator is similar to (but not necessarily identical to) the one used in the standard recursive call.

## Tail Recursion and List Generation

• While tail recursion is generally a good thing, it's a bad idea to spend lots of extra computational effort on building the accumulated partial result.
• The problem appears most frequently in procedures that build lists.
• Consider the problem of adding two to each value in a list.
• Suppose our accumulator contains all the values we've added two to.
• Then at each step, we'll need to put the next value at the end of the accumulator.
• How do you add to the end of a list?
• How much computational effort does it involve?
• You'll find that your procedure spends a lot of time walking through the accumulated result.
• Can we do something better? Yes. Accumulate the reverse of the desired result.
• Updating at each step is each; just cons to the front.
• We do need to spend some extra effort at the end to reverse that result.
• Alternately, we can reverse the parameter before calling the helper.
• See the reading for more details.

## History

Thursday, 16 January 2003 [Samuel A. Rebelsky]

• First version, created mostly automatically from previous course.

Sunday, 13 April 2003 [Samuel A. Rebelsky]

• Updated contents somewhat (made the helper to `suml` local).

Back to Discussion of Exam 2. On to Tail Recursion (2).

Disclaimer: I usually create these pages on the fly, which means that I rarely proofread them and they may contain bad grammar and incorrect details. It also means that I tend to update them regularly (see the history for more details). Feel free to contact me with any suggestions for changes.

This document was generated by Siteweaver on Tue May 6 09:30:13 2003.
The source to the document was last modified on Sun Apr 13 21:39:59 2003.
This document may be found at `http://www.cs.grinnell.edu/~rebelsky/Courses/CS151/2003S/Outlines/outline.41.html`.

You may wish to validate this document's HTML ; ; Check with Bobby

Samuel A. Rebelsky, rebelsky@grinnell.edu