## Session 10

### A Warm-Up Exercise

I occasionally ask you to implement a function that already exists in Racket. Homework 4 contains such a problem. Other times, a student does not read documentation or instructions. (Present company excluded, of course.) As a result, they write functions that already exist, sometimes under a different name. That's not even always a bad thing... Sometimes it's better to use your time practicing than poking around documentation.

 In order to install this Windows Update, you must first install an update for Windows Update. recursive poetry from Microsoft

Write a structurally recursive Racket function (get los n), where los is a list of symbols and n is a non-negative integer. get returns the symbol in position n of los. For example:

```    > (get '(a b c) 2)
'c
> (get '(d c b a z) 1)
'c
> (get '(d c b a z) 10)
get: no such position
```

Make the position 0-based. If n is too big for the list, return an error message as a string.

```    <list-of-symbols> ::= ()
| (<symbol> . <list-of-symbols>)
```

### A Solution for get

Check out a candidate solution in this source file. This is a fine example of using structural recursion to process an inductively-defined datatype.

We can even use get on other kinds of lists, because it never applies a function to the values in the list. As we have seen, a Racket list is a pair whose cdr is a list. We can define generic lists inductively as:

```    <list> ::= ()
| (<any> . <list>)
```
Racket even has a built-in predicate for the "any" datatype, named any/c. We don't need it here, because we don't operate on the items in the list; we only return one of them.

Notice a couple things. First, even though there is a nested if expression in the code, we consider only two kinds of list argument: it is either the empty list or a pair. The second if helps us solve the pair case: Is the item we are looking for in the first part of the pair? Try to think clearly about the different parts of the problem. That will help you make sense of when you need another choice, and why.

Second, if the second argument were a symbol and we wanted to return the position of its first occurrence in the list, like Problem 5 on Homework 4, then we would need something new. Learning that new technique is our first job today.

get is essentially an implementation of Racket's primitive list-ref function, which many of you discovered when not using second or sixth on a previous assignment. You can find many other functions for working with lists in the Racket docs. Most of them are also great exercises for practicing your recursive programming skills!

Finally, my solution uses Racket's primitive error function. Feel free to use it whenever a function has an error case. Note also that we can test our error cases, using another test feature of Rackunit.

### Writing Recursive Programs a web page about a web page about a web page about a web page...

Writing recursive functions well and confidently requires you to know several techniques, just as writing loops well and confidently does. Last session, we explored the basic technique for writing recursive programs, the technique on which we base all of our recursive functions: structural recursion. With this technique, we mimic the structure of an inductive data specification in the code that processes the data.

This idea is simple but powerful. What if we are asked to write a function to process...

• a non-negative integer
• JSON data
• a foo ::= bar | baz | (bif . foo)
?   We can write a template for the function directly from the data type!

This session continues our discussion of recursive programming by introducing two new techniques:

• interface procedure and
• mutual recursion.
These techniques help us to do structural recursion in the face of specific circumstances that we commonly encounter.

### Interface Procedures

Structural recursion is the basis for nearly every function we write. Occasionally, we will encounter bumps along the way to a solution. Rather than pitching structural recursion and flailing at our code without guidance, we will use specific techniques to get over, or around, the bump. Over the next few sessions, we will learn several techniques that we can use when we encounter difficulties using structural recursion. The first of these is the interface procedure.

Unless you are omniscient, writing a recursive function will occasionally require "fixing" the function along the way instead of writing it straight through from beginning to end. Consider the function annotate, which takes as its only argument a <list-of-symbols>. For example, if we pass to annotate

```    (jerry george elaine kramer)
```

it returns a list with each symbol annotated by its position in the list:

```    ((jerry 1) (george 2) (elaine 3) (kramer 4))
```

We can use structural recursion to build the framework of our answer:

```    (define annotate
(lambda (los)
(if (null? los)
; then: handle an empty list
; else: handle a pair
)))
```

The base case of the data spec is the empty list. In this case, an empty list can be returned, since there are no items to annotate:

```    (define annotate
(lambda (los)
(if (null? los)
'()
; else handle a pair
)))
```

The inductive case is a symbol followed by a list of symbols. We can combine the annotated symbol with the rest of the list annotated using cons. The result is:

```    (define annotate
(lambda (los)
(if (null? los)
'()
(cons <something computed from (first los)>
(annotate (rest los))))))
```

When we write a function that computes a list of answers, one for each item in the original list, we will often use a piece of code that looks just like this. It will constitute a common mechanism for "putting our answer back together".

How can we annotate a symbol? By creating a list consisting of the symbol and its position of the symbol in the list:

```    (define annotate
(lambda (los)
(if (null? los)
'()
(cons (list (first los) position)
(annotate (rest los))))))
```

Oops! We've run into a slight problem. We need the position of the symbol in the list, but we haven't supplied it anywhere. We could pass the current position down to each recursive call:

```    (define annotate
(lambda (los position)
(if (null? los)
'()
(cons (list (first los) position)
```

This does the work we need, but we have two related problems:

• What is the initial value of position, the one used on the first call to annotate? The original caller will have to tell annotate to start at position 1!

• annotate is defined to take one argument, but we have produced a function that requires two. We don't usually want to change the spec of a program, even when we have the power to do so, because other parts of our code may rely on the specified interface.

In the case of annotate, changing the interface requires that all calls pass two arguments. Yet we always start annotating with position 1, and now we will have to repeat the 1 in every "first call" call to annotate.

Finally, we will no longer be able to map this function over a list of lists, because it takes two arguments. map requires a one-argument function. By taking map and similar higher-order functions out of our toolbox, we give up much of the power and productivity in the functional style.

These reasons should persuade us to look for a different solution. Programmers face this problem all of the time and have developed a common "patch". First, rename this version of the solution as a helper function:

```    (define annotate-with-position
(lambda (los position)
(if (null? los)
'()
(cons (list (first los) position)
```

Second, implement annotate as a function that calls the renamed function:

```    (define annotate                   ;; now write annotate ...
(lambda (los)                   ;; ... to jump-start the helper
(annotate-with-position los 1)))
```

We call the new annotate an interface procedure. It serves as an interface to the function that does the real work.

Creating an interface procedure is a common practice in many kinds of programming, including functional programming. It allows us to write our code naturally -- in the way that follows our understanding of the problem -- even when the task becomes complicated, without disturbing the tranquility of the world in which the function resides.

The interface function pattern illustrates a valuable wisdom: When you encounter a difficulty implementing structural recursion, don't give up on the technique. We are following the structure of our data for many good reasons. Instead of giving up, solve the new difficulty. The problem we encountered while implementing annotate is so common that other programmers have developed a standard solution. This wisdom generalizes beyond structural recursion to any well-justified technique, including most every design pattern we use.

### A New Wrinkle: subst

Last session, we defined two functions, remove-upto and remove-first, over lists of symbols. List of symbols is the data type on which they operate, and we had an inductive definition for the type that guided our work. Today, let's consider a more complex data structure, one that will be of great use to us when we write programs to process languages: the s-list. The difference between a list of symbols and an s-list is that the elements of the list can themselves be s-lists.

Here is the BNF notation for an s-list:

```               <s-list> ::= ()
| (<symbol-expression> . <s-list>)

<symbol-expression> ::= <symbol>
| <s-list>
```

And here are some examples:

```       ()                           (())
(a)                          ((a) b)
(a b c)                      (a (b) c)
(a b c d)                    (if (zero? n) zero (/ total n))
(a b c d e f g h)            (cons (foo (car x)) (foo-cdr (cdr x)))
```

The items on the left are lists of symbols, but they are also s-lists. A symbol-expression can be a symbol, or an s-list.

Let's define a function, subst, that substitutes one symbol for another anywhere in an s-list. You can think of this as like a global "search and replace" operation. For example, when applied to a program, subst can serve as the foundation of an operation for renaming variables -- a common refactoring that all programmers do.

This function takes three arguments: the new symbol, the old symbol, and an s-list to operate on:

```    >  (subst 'd 'b '(a b c a b c d))
(a d c a d c d)

> (subst 'a 'b '((a b) (((b g r) (f r)) c (d e)) b))
((a a) (((a g r) (f r)) c (d e)) a)
```

Following the principle of structural recursion, the structure of subst should follow the structure of the BNF specification for an s-list:

```    (define subst
(lambda (new old slist)
(if (null? slist)
;; handle the empty list
;; handle a pair that contains a symbol-expression
)))
```

If slist is empty, there are no occurrences of old to replace. The answer is the empty list.

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
;; handle a pair containing a symbol-expression
)))
```

The second arm of our BNF definition defines a case where slist is a pair with the form (<symbol-expression> . <s-list>). The result of subst will be the result of substituting new for old in both parts, the <symbol-expression> and the <s-list>.

The first element of the pair is a symbol-expression. Note, however, that symbol-expression is also defined in terms of a choice. Our natural inclination might be to implement this choice with a conditional expression. There are two alternatives: the first element is a symbol, or it is an s-list.

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
(if (symbol? (first slist))
;; handle a symbol in the first, handle slist in the rest
;; handle an slist in the first, handle slist in the rest
))))
```

We have to return a list with the same structure as our input, so in both cases we cons the result from the first into the result from the rest.

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
(if (symbol? (first slist))
(cons ;; handle symbol in first ;; handle slist in rest)
(cons ;; handle slist in first  ;; handle slist in rest)
))))
```

If it is a symbol, we must determine whether or not to replace it with new. We replace the symbol if it is equal to old, and otherwise we leave it alone:

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
(if (symbol? (first slist))
(if (eq? (first slist) old)
(cons new           ;; handle the slist in the rest )
(cons (first slist) ;; handle the slist in the rest )
(cons ;; handle slist in first  ;; handle slist in rest)
))))
```

In both of these cases, we need to substitute new for old in the rest of the list. The rest is an s-list, so we can use subst to compute that part of our result.

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
(if (symbol? (first slist))
(if (eq? (first slist) old)
(cons new           (subst new old (rest slist)))
(cons (first slist) (subst new old (rest slist)))  )
(cons ;; handle slist in first  ;; handle slist in rest)
))))
```

The only thing left to do is to decide what to do when the first member of slist is not a symbol. In that case, it is an s-list. We are in luck. We already have a function for substituting symbols in s-lists. It is the function that we are writing, subst! So, we can:

• substitute new for old in the first of the list,
• substitute new for old in the rest of the list, and
• construct a new pair consisting of these two results.
The code looks like this:
```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
(if (symbol? (first slist))
(if (eq? (first slist) old)
(cons new (subst new old (rest slist)))
(cons (first slist)
(subst new old (rest slist)))  )
(cons (subst new old (first slist))
(subst new old (rest slist)))))))
```

And we are done, or at least we have a working solution. Our basic structural recursion technique guided us along the way. But is this a good solution?

Programming Aside: Notice how the indentation of this code makes the control structures we are using as clear as possible. Whenever you write a program -- especially in a language like Racket (with a uniform syntax (and so (many) function calls!)) -- you should strive to write code that tells us how to read itself.

### The Wrinkles

Our function works but, if we are honest with ourselves, we must admit that it has a couple of weaknesses.

First, we have repeated the expression (subst new old (rest slist)) three times, including twice in the if expression that handles symbols. We know that repeated code can cause all sorts of problems in maintenance. But having to write these expressions separately also makes it hard for us to write the function in the first place. A mistake, even a typo, in any of the expressions will break our function. Besides, all the repetition makes the code harder to read.

Second, it is not really faithful to the structure suggested by the BNF. Look at the definition of an s-list again:

```               <s-list> ::= ()
| (<symbol-expression> . <s-list>)

<symbol-expression> ::= <symbol>
| <s-list>
```

Structural recursion tells us that the structure of our code should reflect the structure of the data. Our code does not. There are two BNF expressions in the data definition, but we have written only one function!

The second weakness causes the first. By not following the data structure, we have created extra cases to solve and made the problem harder to solve. That is what requires us to duplicate code.

If you look back at the step-by-step evolution of our function, you will see a clue hinting at this second weakness. We had to leave ourselves detailed notes using comments so that we did not lose our place as we solved small parts of the problem. Those comments are a sign that we are managing a lot of complexity in our heads. But the data type we are processing is not that complex!

My running commentary does more than give us a clue about when we went off track. It tells us exactly where we went off track:

The first element of the pair is a symbol-expression. Note, however, that symbol-expression is also defined in terms of a choice. Our natural inclination might be to implement this choice with a conditional expression. ...

A better way to reflect the choice between kinds of symbol expression would be to follow the data definition. An s-list is defined in terms of symbol expressions, and a symbol expression is defined in terms of s-lists. We say that such data types are mutually inductive. We'd like for our code to show this relationship, too.

Patterns that show up in data should probably show up in the code that processes the data. (And perhaps in the languages we use to write the code...)

### Mutual Recursion: A Better subst For our program structure to follow the pattern of the BNF, we must define a function for substituting symbols in s-lists, called subst, and a function for substituting symbols in symbol expressions, called, say, subst-symbol-expr. Because each data type is defined in terms of the other, these functions will call one another. This technique is called mutual recursion, because the recursion involves two functions that call one another, working together to create a solution.

Let's begin again and write subst from scratch. For now, let's suppose that subst-symbol-expr exists.

```    (define subst
(lambda (new old slist)
(if (null? slist)
'()
;; handle a pair that contains a symbol-expression
)))
```

The "else" clause becomes quite easy to write:

• substitute new for old in the first of the s-list using subst-symbol-expr,
• substitute new for old in the rest of the s-list using subst, and
• make a new pair from the results using cons.

The definition of subst becomes:

```   (define subst
(lambda (new old slist)
(if (null? slist)
'()
(cons (subst-symbol-expr new old (first slist))
(subst new old (rest slist)))   )))
```

Isn't that much clearer?

Now we have to write subst-symbol-expr. Using structural recursion, the definition of this function follows the BNF definition of the data type it processes, a symbol expression. The BNF lists two alternatives for a symbol expression: it is either a symbol, or it is an s-list. So:

```    (define subst-symbol-expr
(lambda (new old symexp)
(if (symbol? symexp)
;; handle a symbol
;; handle an slist
)))
```

If the symbol expression is a symbol, then we decide whether to replace it with the new symbol:

```    (define subst-symbol-expr
(lambda (new old symexp)
(if (symbol? symexp)
(if (eq? symexp old)
new
symexp)
;; handle an slist
)))
```

If not, then it is an s-list. But we have already written a function that can make substitutions in an s-list: subst! Call it:

```    (define subst-symbol-expr
(lambda (new old symexp)
(if (symbol? symexp)
(if (eq? symexp old)
new
symexp)
(subst new old symexp))))
```

That's pretty clear, too.

Our solution now consists of two relatively small, relatively simple functions that work together to solve the problem.

What are the advantages of our new program?

• It now follows more closely the BNF definition of the s-list data type, which consists of two types of expression. This makes the code easier to read and modify, because readers can easily find the parts of the program they care about from the parts of the data definition.

• We have simplified the definition considerably. Nested ifs can be hard to understand and trace, even for experienced programmers using good programming style. We now have only one nested if, and it is simpler than the same nesting we did in our first function.

• We don't repeat code, in particular the three uses of subst on the rest of the s-list, or multiple calls to first and rest.

• Defining separate functions for each non-terminal in the BNF breaks the programming process into manageable parts and allows us to concentrate our efforts on one thing at a time.

Mutual recursion will be our technique of choice whenever we have a multiple-part data definition.

### An Exercise: count-occurrences

Use mutual recursion to implement (count-occurrences s slist), which counts how many times the symbol s occurs in slist.

For example:

```   > (count-occurrences 'a '(a b c))
1

> (count-occurrences
'a '(((a be) a ((si be a) be (a be))) (be g (a si be))))
5
```

The first step is to examine the BNF:

```               <s-list> ::= ()
| (<symbol-expression> . <s-list>)

<symbol-expression> ::= <symbol>
| <s-list>
```

From the BNF, we expect to write two functions, one that counts the symbol in an s-list and one that counts the symbol in a symbol expression.

```    (define count-occurrences
(lambda (s slist)
(if (null? slist)
;; slist is empty
;; slist is a pair
)))
```

We can conclude without much effort that a symbol occurs in an empty list 0 times. In a non-empty list, the number of times it occurs is equal to the number of times it occurs in the first part of the list plus the number of times it occurs in the rest of the list.

Because this is a mutually recursive specification and function, we will assume that a function named count-occurrences-sym-expr exists, so that we can use it to count the number of occurrences in the car of the pair:

```    (define count-occurrences
(lambda (s slist)
(if (null? slist)
0
(+ (count-occurrences-sym-expr s (first slist))
(count-occurrences s (rest slist)))  )))
```

Now, we define count-occurrences-sym-expr. The BNF description for symbol expressions suggests the following pattern:

```    (define count-occurrences-sym-expr
(lambda (s sym-expr)
(if (symbol? sym-expr)
;; sym-expr is a symbol
;; sym-expr is an slist
)))
```

If the symbol expression is a symbol, then we need to determine whether it is the symbol we're counting or not and return the appropriate value, 0 or 1. If it is an s-list, then we have a function for counting occurrences -- count-occurrences:

```    (define count-occurrences-sym-expr
(lambda (s sym-expr)
(if (symbol? sym-expr)
(if (eq? s sym-expr) 1 0)
(count-occurrences s sym-expr) )))
```

And we are done!

### Wrap Up

• Reading -- Review the lecture notes. Try to write the code again from scratch. Review the code.

Then read a short section on increasing efficiency through program derivation, which we will review next time.

• Homework 4 is available and is due next session. All the problems require "vanilla" structural recursion, no mutual recursion needed. Homework 5 will be available then.

Eugene Wallingford ..... wallingf@cs.uni.edu ..... February 16, 2023