the little racketeer – 06

The first part of this chapter introduces us to the concept of recurring through deeper lists by iterating on the previously written procedure rember, which removed instances of a given atom from a list, but only worked on what I call “flat lists” (lists which contain only atoms). They prompt with a scaffold after two examples, about which I have a little extended discussion.

With this one, I noticed my solutions are starting to differ more from the text. In this example, the text uses a nested cond block:

(define rember*
  (lambda (a l)
    (cond
      ((null? l) '())
      ((atom? (car l)
        (cond
          ((eq? (car l) a)
           (rember* a (cdr l)))
          (else (cons (car l)
                  (rember* a (cdr l))))))
      (else (cons (rember* a (car l))
                  (rember* a (cdr l)))))))

My solution

(define myrember*
  (λ (a l)
    (cond
      ((null? l) '())
      ((list? (car l))
       (cons (myrember* a (car l)) 
             (myrember* a (cdr l))))
      ((eq? a (car l)) (myrember* a (cdr l)))
      (else (cons (car l) (myrember* a (cdr l)))))))

null? is a terminating condition, so test that first. then testing if the first element of l is itself says if it is, basically recur through that sub-list and combine the results with (cdr l), but if (car l) is not a list or null, then it is atomic (if the input follows The Law of Cons), so we can remove that if it is equal to a. Finally else leads to the natural recursion. No need for nested cond blocks.

Since the text uses atom? and I used list?, I thought that my solution might not be correct. I wrote a little test to see how myrember* and rember* deal with non-list pairs. It turns that that either procedure works for the examples in the text, and both fail if you put a non-list pair inside l because both procedures assume that (cdr l) is always a list in the recursive calls of myrember*/rember*.

📌When is a pair that is not a list useful?

This chapter “finalizes” the First Commandment:

My intuition leads me to ask (list? l). Is there a good reason not to?

The Fifth Commandment is finalized as:

Finally, we get a Sixth Commandment warning us against premature optimization:

The remaining procedures in the chapter are straightforward adaptations of older procedures into versions that accept lists of S-expressions, but repetition is good for the brain.