3

I'm currently reading the 4th edition of "The Little Schemer". One early exercise is to create a function insertR which inserts an value to the right of a given value in a list. The book eventually arrives at the following definition:

(define insertR
  (lambda (new old lat)
    (cond
      ((null? lat) (quote ()))
      (else (cond
              ((eq? (car lat) old)
               (cons old
                     (cons new (cdr lat))))
              (else (cons (car lat)
                          (insertR new old
                                   (cdr lat)))))))))

My own definition looked like this:

(define insertR
  (lambda (new old lat)
    (cond
      ((null? lat) (quote ()))
      ((eq? (car lat) old) (cons old (cons new (cdr lat))))
      (else (cons (car lat) (insertR new old (cdr lat)))))))

Are they equivalent?

John Clements
  • 16,895
  • 3
  • 37
  • 52
Andreas Brinck
  • 51,293
  • 14
  • 84
  • 114
  • 1
    I believe noone ever gonna search your title( _Are the following functions equivalent_) in one of the search engines... Can't you improve it? – gdoron Sep 23 '12 at 17:24
  • Yes, I think you're right. I changed it to something hopefully better, feel free to change it though. – Andreas Brinck Sep 24 '12 at 06:42
  • Somehow, the hint from gdoron gave his fruits: I'm reading The Little Schemer right now and searched for someone who noticed the same thing :) However, as someone else stated, on page 41 the authors seem to encourage this kind of simplification. – Alberto Moriconi Nov 23 '12 at 22:33

4 Answers4

3

Of course both definitions are equivalent, but your definition is easier to read. Bear in mind that you're only in the 3rd chapter of the book, and the authors like to go slowly. Later in the same chapter, on page 41 they'll teach you precisely the kind of simplification that you're doing - dealing with all mutually exclusive conditions in a single cond form, instead of nesting cond forms.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Actually the example I'm referring to is on page 47, after they've shown how to do some simplifications. I kept waiting for them to simplify this example as well but they never did. – Andreas Brinck Sep 24 '12 at 06:45
3

Yes, the two definitions have the same behavior.

The reason the book has two conds is because they are serving two different purposes. The outer cond distinguishes between the two cases of the list datatype (a list is either null or a cons whose second argument is a list). The outer cond is determined by the typed of data being consumed; all structurally-recursive functions on lists will have that outer cond. The inner cond is specific to the particular function being defined.

So, while it is more compact to combine them, by leaving them separate you make the structure of the function correspond more clearly to the structure of the recursive type. If you use that idiom consistently, it makes your structurally-recursive functions easier to read, debug, and maintain.

Ryan Culpepper
  • 10,495
  • 4
  • 31
  • 30
3

I'm going to say the same thing as Ryan: readability is second only to correctness. In fact, if you're a student, readability may be more important than correctness.

The advantage of the version that appears in the book is that it has a two-armed cond where one tests for emptiness. This is the totally normal and expected way to break down the problem. When I see this split, I can swiftly understand the role of the two blocks of code. In your code, I have to stop and spend time to make sure that the three cases are exhaustive and mutually exclusive, and then deduce which inputs fall into which bins.

Here's what I want you to picture: it's 11:52 PM, I'm tired, my eyes hurt, and I'm reading over forty-five solutions to the same problem, written by students. I'm looking for CLARITY, darn it. If you can write your solution in a way that makes it OBVIOUS that you did it right, I'm going to give you 100% and bless your name.

John Clements
  • 16,895
  • 3
  • 37
  • 52
  • 1
    I see where you're coming from, but the older I get the more I appreciate conciseness, the less code I have too read, the easier it is for me to understand what a function does. But it's a matter of opinion, for sure. – Andreas Brinck Sep 24 '12 at 08:20
2

They are, yes, though I find yours easier to read. cond supports multiple clauses, and evaluates each until one of them evaluates to a true value. Thus, the following:

(else (cond
        ((eq? (car lat) old) (cons old (cons new (cdr lat))))
        (else (cons (car lat) (insertR new old (cdr lat)))))))))

Is equivalent to moving the first clause of the second cond to the first one:

(cond
  ((null? lat) (quote ()))
  ((eq? (car lat) old) (cons old (cons new (cdr lat))))
  (else (cons (car lat) (insertR new old (cdr lat)))))))

Perhaps the authors of the book thought it was more clear to separate the terminal null condition from the two others, but if that were the case, and if would suffice instead of cond.

João Silva
  • 89,303
  • 29
  • 152
  • 158