Let's try the conversion-to-accumulator process again on another
simple accumulator program.  Write an accumulator version of sum,
which consumes a list of numbers and produces a number (the sum of all
elements in the list).  As always, start with the structural version
and work from there.  We'll call this program old-sum because we'll
want to compare this version and the accumulator version later in the
class.

;; old-sum : (listof number) -> num
;; computes the sum of all the numbers in the list
(define (old-sum alon)
  (cond [(empty? alon) 0]
	[else (+ (first alon) (old-sum (rest alon)))]))

First, we develop a skeleton of the program, leaving a space for the
description of the accumulator:

;; sum : (listof number) -> num
;; computes the sum of all the numbers in the list
(define (sum alon)
  (local [;; accum : ...
          (define (sum-accum a-lon accum)
	    (cond [(empty? a-lon) ...]
		  [else ... (sum-accum (rest a-lon)
				   ... (first a-lon) ... accum ... )]))]
     (sum-accum alon ...)))

Then we fill in the accumulator description and the final program:

;; sum : (listof number) -> num
;; computes the sum of all the numbers in the list
(define (sum alon)
  (local [;; accum : contains the sum of all numbers in alon that
          ;;  precede a-lon.
          (define (sum-accum a-lon accum)
	    (cond [(empty? a-lon) accum]
		  [else (sum-accum (rest a-lon)
				   (+ (first a-lon) accum))]))]
     (sum-accum alon 0)))

Let's compare this to our old definition of sum: How do these two
programs differ in how they compute a result?

  (old-sum (list 2 5 3 7))
= (+ 2 (old-sum (list 5 3 7)))
= (+ 5 (+ 2 (old-sum (list 3 7))))
= (+ 3 (+ 5 (+ 2 (old-sum (list 7)))))
= (+ 7 (+ 3 (+ 5 (+ 2 (old-sum empty)))))
= (+ 7 (+ 3 (+ 5 (+ 2 0))))
= (+ 7 (+ 3 (+ 5 2)))
= (+ 7 (+ 3 7))
= (+ 7 10)
= 17

  (sum (list 2 5 3 7))
= (sum-accum (list 2 5 3 7) 0)
= (sum-accum (list 5 3 7) 2)
= (sum-accum (list 3 7) 7)
= (sum-accum (list 7) 10)
= (sum-accum empty 17)
= 17

Notice the different shapes of these two computations.  The first
stacks up like an arrow, which the second remains rather rectangular.
This is a standard difference between programs that use accumulators
and programs that use plain structural recursion.  This difference
matters because it can affect how a program runs on your computer.  If
you try a large enough example, the amount of pending computation that
you build up could exhaust the available resources in your machine,
thus preventing the computation from finishing.  In the accumulator
version, you don't build up pending computation, so this isn't a
problem. 

One more problem of accumulators on lists.  Let's look at max-of-list.

(define (max-of-list anelon)
  (cond [(empty? (rest anelon)) (first anelon)]
	[else (max (first anelon)
		   (max-of-list (rest anelon)))]))

We start as we did before, writing a template for the accumulator program.

(define (max-of-list anelon)
  (local [;; accum : ...
	  (define (max-accum alon accum)
	    (cond [(empty? (rest alon)) ...]
		  [else (max-accum (rest alon)
				   ... (first alon) ... accum )]))]
    (max-accum anelon ...)))

Now, fill in the accumulator description and the holes.

(define (max-of-list anelon)
  (local [;; accum : max number in portion of anelon that precedes alon
	  (define (max-accum alon accum)
	    (cond [(empty? (rest alon)) (max (first alon) accum)]
		  [else (max-accum (rest alon)
				   (max (first alon) accum))]))]
    (max-accum anelon ...)))

There are two things to notice here.  First, it's still not clear how
to fill in the ... in the bottom call to max-accum.  Second, notice
that we have the expression (max (first alon) accum) in the program
twice.  Having the same expression in both the base case and the
recursive case should suggest that there is something wrong with our
program.

Let's look at the missing ... first.  Why is this hard to fill in?
Because according to our statement about the accumulator, the
accumulator should hold the max number in the portion of anelon that
precedes alon.  However, initially, alon and anelon are the same list,
so there is no such number.  That suggests a problem.  One option is
to change the accumulator description, but that looks correct aside
from this initial case.  Another option is to change the argument that
we first pass to alon so that alon and anelon are different on the
first iteration.  We know that anelon is a non-empty list of numbers,
so what if we past (rest anelon) as the first value of alon, leaving
(first anelon) as the initial value of the accumulator.

(define (max-of-list anelon)
  (local [;; accum : max number in portion of anelon that precedes alon
	  (define (max-accum alon accum)
	    (cond [(empty? (rest alon)) (max (first alon) accum)]
		  [else (max-accum (rest alon)
				   (max (first alon) accum))]))]
    (max-accum (rest anelon) (first anelon))))

That seems fine, but still leaves the duplicated max computation
though.  Where did we get the structure of max-accum from?  We wrote
it assuming that alon was a non-empty list, just like anelon.
However, now that we start alon with (rest anelon), alon is really
(listof number), not a non-empty list of numbers.  So, we should
rewrite max-accum using the template for a regular list of numbers.
This changes the base case, so let's reintroduce ... in the answer for
the base case.

(define (max-of-list anelon)
  (local [;; accum : max number in portion of anelon that precedes alon
	  (define (max-accum alon accum)
	    (cond [(empty? alon) ...]
		  [else (max-accum (rest alon)
				   (max (first alon) accum))]))]
    (max-accum (rest anelon) (first anelon))))

Now, looking at our new skeleton, what should we put in for the ...?
Based on the accumulator statement, all we need is the accumulator
itself!  Thus, we finish the program as follows:

(define (max-of-list anelon)
  (local [;; accum : max number in portion of anelon that precedes alon
	  (define (max-accum alon accum)
	    (cond [(empty? alon) accum]
		  [else (max-accum (rest alon)
				   (max (first alon) accum))]))]
    (max-accum (rest anelon) (first anelon))))

The point of doing max was to show you that sometimes you have to
rewrite parts of your program to convert it into accumulator style.
However, you have all the tools of good design -- recipes, accumulator
descriptions, and templates -- to help you talk yourself through the
process.

Let's try another program.  Recall the data definition for a file
system.  Let's write a program to get the names of all files in the
directory hierarchy.

A file is a symbol (representing its name)

A dir is a structure
  (make-dir n ds fs)
where n is a symbol, ds is a (listof dir) and fs is a (listof file)

(define-struct dir (name dirs files))

;; get-all-files : dir -> (listof symbol)
;; creates a list of all file names in the directory hierarchy
(define (get-all-files a-dir)
  (append (dir-files a-dir)
	  (get-files-dirlist (dir-dirs a-dir))))

;; get-files-dirlist : (listof dir) -> (listof symbol)
;; get all file names from a list of directories
(define (get-files-dirlist alod)
  (cond [(empty? alod) empty]
	[else (append (get-all-files (first alod))
		      (get-files-dirlist (rest alod)))]))

Notice that both programs have the characteristic that we discussed in
the last class: they use a recursive program to process the result of
a (mutually) recursive call to process more of the structure.  This
program is therefore a good candidate for an accumulator.  We should
start with the same skeleton-building process that we used for
accumulator programs on lists:

;; get-all-files : dir -> (listof symbol)
;; creates a list of all file names in the directory hierarchy
(define (get-all-files adir)
  (local [; accum1 : ...
	  (define (get-files-accum a-dir accum1)
	    (get-dirlist-accum (dir-dirs a-dir) ...
			       (dir-files a-dir) ... accum1 ...))
	  ; accum2 : ...
	  (define (get-dirlist-accum alod accum2)
	    (cond [(empty? alod) ...]
		  [else (get-dirlist-accum
			 (rest alod) ... 
			 (get-files-accum (first alod) ... accum2))]))]
    (get-files-accum adir ...)))

Next, fill in the descriptions of the accumulators

;; get-all-files : dir -> (listof symbol)
;; creates a list of all file names in the directory hierarchy
(define (get-all-files adir)
  (local [; accum1 : contains all files in directories above and to the left of
	  ;  a-dir in the directory tree adir
	  (define (get-files-accum a-dir accum1)
	    (get-dirlist-accum (dir-dirs a-dir) ...
			       (dir-files a-dir) ... accum1 ...))
	  ; accum2 : contains all files in directories in adir that are above and
	  ;  to the left of directories in alod
	  (define (get-dirlist-accum alod accum2)
	    (cond [(empty? alod) ...]
		  [else (get-dirlist-accum
			 (rest alod) ... 
			 (get-files-accum (first alod) ... accum2))]))]
    (get-files-accum adir ...)))

Finally, fill in the holes based on the descriptions of the accumulators.

(define (get-all-files adir)
    (local [; accum-f1 : contains all files in directories above and to the
	    ;  left of a-dir in the directory tree adir
	    (define (get-files-accum a-dir accum-f1)
	      (get-dirlist-accum (dir-dirs a-dir)
		                 (append (dir-files a-dir) accum-f1)))
	    ; accum-f2 : contains all files in directories in adir that
	    ;  are above and to the left of directories in alod
	    (define (get-dirlist-accum alod accum-f2)
	      (cond [(empty? alod) accum-f2]
		    [else (get-dirlist-accum
			    (rest alod)
			    (get-files-accum (first alod) accum-f2))]))]
      (get-files-accum adir empty)))