# Course 287: Lecture 9 Deep Lists and Deep Recursion

Deep Lists can be thought of as Trees.
Using An Accumulator to Make Computation More Efficient.
Association lists provide finite mappings.

#### Functions Defined in this Lecture.

(occurs_atom? a l) finds if atom a occurs in list structure l
(count_occurrences a l) finds if atom a occurs in list structurel
(subst x y expr) replaces all occurrences of atom x by y in list structureexpr
(assoc x alist)finds entry for x in alist
(assq x alist)finds entry for x in alist, using eq?
(assv x alist)finds entry for x in alist
(lookup x alist)finds value for x in alist
(flatten tree) makes a list of all the objects stored in nodes of tree.
(reverse l) makes a list of the objects of l in reverse order

## Deep Lists can be thought of as Trees.

Given a deeply-nested list such as:

```            (a ((b c)) (d (e (f))) g)
```

it is often useful to visualise it as a tree written out as follows:

```            (a ((b c)) (d (e (f))) g)
|
----------------------------------------
|         |              |             |
a      ((b c))      (d (e (f)))        g
|              |
|          ----------
|          |        |
(b c)        d     (e (f))
|                   |
------             --------
|    |             |      |
b    c             e     (f)
|
f

```

In order to explore this whole tree, that is to visit every sublist of a list, we need to use deep-recursion. A function is deeply recursive if it is called recursively on the car of a list as well as on its cdr.

#### occurs_atom? and count_occurrences

For example, we may write a function occurs_atom? to find out if a given atom (non-pair) occurs anywhere in a nested list:
``````
(define (occurs_atom? x expr)
(cond
((atom? expr) (eqv? x expr))
(else (or
(occurs_atom? x (car expr))
(occurs_atom? x (cdr expr))
))
)
)
``````
``````
(example '(occurs_atom? 'a '(b (c d ((a))))) #t)
``````
Instead of merely reporting on the existence of an atomic quantity in a list-structure, we may want to report on how many times it occurs. The above function is quite easily modified to do this.
``````
(define (count_occurrences x expr)
(cond
((atom? expr) (if (eqv? x expr) 1 0))
(else (+
(count_occurrences x (car expr))
(count_occurrences x (cdr expr))
))
)
)
``````
``````
(example '(count_occurrences 'a '((b (c)) (a) (b ((a))))) 2)
``````

Let us use trace to see how count_occurrences works.

``````
(trace count_occurrences)
``````

If we now call

``````
(count_occurrences 'a '(b (a) (b (c a))))
``````

we obtain the following print-out italics were inserted by the author.

``` (count_occurrences  a  (b (a) (b (c a))) )  top level call
|(count_occurrences  a  b  )                recursive call on car of list
|count_occurrences   = 0                    a does not occur in b
|(count_occurrences  a  ((a) (b (c a))) )   now do cdr of original list
| (count_occurrences  a  (a) )              and do its car
| |(count_occurrences  a  a  )              and the car of that
| |count_occurrences   = 1                  in which a occurs once.
| |(count_occurrences  a  () )              and  do the cdr of '(a)
| |count_occurrences   = 0                  in which a  does not occur
| count_occurrences   = 1                   so  a occurs once in '(a)
| (count_occurrences  a  ((b (c a))) )
| |(count_occurrences  a  (b (c a)) )
| | (count_occurrences  a  b  )
| | count_occurrences   = 0
| | (count_occurrences  a  ((c a)) )
| | |(count_occurrences  a  (c a) )
| | | (count_occurrences  a  c  )
| | | count_occurrences   = 0
| | | (count_occurrences  a  (a) )
| | | |(count_occurrences  a  a  )
| | | |count_occurrences   = 1
| | | |(count_occurrences  a  () )
| | | |count_occurrences   = 0
| | | count_occurrences   = 1
| | |count_occurrences   = 1
| | |(count_occurrences  a  () )
| | |count_occurrences   = 0
| | count_occurrences   = 1
| |count_occurrences   = 1
| |(count_occurrences  a  () )
| |count_occurrences   = 0
| count_occurrences   = 1
|count_occurrences   = 2
count_occurrences   = 2
```

#### The subst function.

If we are mechanising any aspect of mathematics we are going to want to implement the substitution operation, in which one sub-expression is systematically replaced by another sub-expression throughout an entire large expression. Typically, we may replace a variable by an expression. Here is a function which substitutes for variables.
``````
(define (subst x y expr)
(if
(atom? expr)
(if (eq? x expr) y expr)
(cons (subst x y (car expr))
(subst x y (cdr expr))
)
)
)
``````

## Using An Accumulator to Make Computation More Efficient.

#### The flatten function

Consider the function flatten which takes a tree and makes a (flat) list of all the "tips" of the tree.

``````
(define (flatten tree)
(cond
((null? tree) '())
((atom? (car tree)) (cons (car tree) (flatten (cdr tree))))
(else
(append (flatten (car tree))
(flatten (cdr tree)))))
)
``````
``````
(example '(flatten '((b (c)) (a) (b ((a))))) '(b c a b a))
``````

Notice that flatten has complexity O(n^2) - it takes O(n) operations to do an append, and this is done O(n) times.

We can make a more efficient tree-flattening function using an accumulator. In the following definition, the accumulator ans can be regarded as a kind of basket. We crawl all over the tree, "picking cherries", that is the things we want to find in the tree, and putting them in the basket.

``````
(define (flatten2 tree ans)
(cond
((null? tree) ans)
((atom? tree) (cons tree ans))
(else
(flatten2 (car tree) (flatten2 (cdr tree) ans)))
)
)
``````
``````
(define (flatten tree) (flatten2 tree '()))
``````
``````
(example '(flatten '((a b (c)) (d) (e ((f))))) '(a b c d e f))
``````
``````
(example '(subst 'a 3 '(+ (* a 7) b)) '(+ (* 3 7) b))
``````

#### (reverse l> makes a list of the elements of l in reverse order

The simple recursive definition of reverse is this:
``````
(define (reverse l)
(if (null? l)
'()
(append (reverse (cdr l)) (list (car l)))
)
)
``````
``````
(example '(reverse '(1 2 3)) '(3 2 1))
``````
But we can make a more efficient version using accumulation thus:
``````
(define (reverse l)
(reverse_1 l '())
)
``````
``````
(define (reverse_1 l acc)
(if (null? l)
acc
(reverse_1 (cdr l) (cons (car l) acc))
)
)
``````
``````
(reverse '(2 3 4))
(4 3 2)
``````

## Association lists provide finite mappings.

Often in computing we want to set up a finite mapping that relates one finite set to another. For example we may want to represent the fact that a variable a has the value 1, b has the value 2 and c has the value 3. We can represent such a mapping using an association list or alist:

``````
(define e '((a 1) (b 2) (c 3)))
``````

In order to access and update such alists, Scheme provides 3 functions assoc, assq and assv. They all take two arguments. The first of these is a "key" and the second is an alist. The key is compared successively with the first element of each sub-list of the alist. The first sub-list whose first member "matches" the key is returned as the result of the function. If no match is found, false is returned.

``````
(example '(assoc 'b e) '(b 2))
``````

The difference between assoc, assq and assv lies in the equality function used to test for matching. assoc uses the equal function, and provides a capability that is generally useful, but may be rather slow. assq and assv use eq? eqv? respectively.

``````
(example '(assq 'a e) '(a 1))
(example '(assq 'b e) '(b 2))
(example '(assq 'd e) #f)
(example '(assq '(a) '(((a) 4) ((b) 5) ((c) 7) )) #f)

(example '(assoc (list 'a) '(((a)) ((b)) ((c)))) '((a)))
(example '(assq 5 '((2 3) (5 7) (11 13))) '(5 7))   ; ** see note below
(example '(assv 5 '((2 3) (5 7) (11 13))) '(5 7))
``````

** Note - the Scheme standard does not specify what the result of using eq? to compare numbers is, so this example may produce different results with different implementations of Scheme.

We could define assoc as follows:

``````
(define (assoc obj alist)
(cond
((null? alist) #f)
((equal? obj (caar alist)) (car alist))
(else (assoc obj (cdr alist)))
))
``````

### The lookup function

Typically we will use assoc to locate the sublist in which a value resides, and then take the appropriate action to find the value. For example, an interpreter for a programming language might say something like:

```  (if (symbol? expr) (lookup expr environment) expr)
```

where the lookup function is defined as:

``````
(define (lookup var env)           ;;; find the value of a variable
(let ((pair (assoc var env)))    ;;; find where its value is held
(if pair                     ;;; does an entry exist for the variable?
(cadr pair)              ;;; extract its value
(error "unbound variable" var)
) ) )
``````