Search code examples
lambdaschemecontinuationsthe-little-schemer

The Little Schemer: stuck on multiinsertLR&co example


I was able to grok the multirember&co function after some work, but I can't really make much sense out of the following multiinsertLR&co code (p. 143):

(define multiinsertLR&co
  (lambda (new oldL oldR lat col)
    (cond
     ((null? lat)
      (col '() 0 0))
     ((eq? (car lat) oldL)
      (multiinsertLR&co
       new
       oldL
       oldR
       (cdr lat)
       (lambda (newlat L R) 
         (col (cons new
                    (cons oldL newlat))
              (add1 L) R))))
     ((eq? (car lat) oldR)
      (multiinsertLR&co
       new
       oldL
       oldR
       (cdr lat)
       (lambda (newlat L R)
         (col (cons oldR
                    (cons new newlat))
              L (add1 R)))))
     (else
      (multiinsertLR&co
       new
       oldL
       oldR
       (cdr lat)
       (lambda (newlat L R)
         (col (cons (car lat)
                    newlat) L R)))))))

The book doesn't seem to explain which collector one should initially pass when evaluating the function, so I used the a-friend collector and last-friend collector explained on pages 138 and 140, respectively. Evaluating the function with either collector results in the following error (using the trace function with petit chez scheme):

>> (multiinsertLR&co 'salty 'fish 'chips '(chips and fish or fish and chips) last-friend)

|(multiinsertLR&co salty fish chips (chips and fish or fish and chips)
   #<procedure>)
|(multiinsertLR&co salty fish chips (and fish or fish and chips)
   #<procedure>)
|(multiinsertLR&co salty fish chips (fish or fish and chips) #<procedure>)
|(multiinsertLR&co salty fish chips (or fish and chips) #<procedure>)
|(multiinsertLR&co salty fish chips (fish and chips) #<procedure>)
|(multiinsertLR&co salty fish chips (and chips) #<procedure>)
|(multiinsertLR&co salty fish chips (chips) #<procedure>)
|(multiinsertLR&co salty fish chips () #<procedure>)
Exception: incorrect number of arguments to #<procedure>
Type (debug) to enter the debugger.

I looked over the code several times, but couldn't find the error. If someone has any insight, please share it. If anyone could also point me to a (relatively speaking) gentle explanation of continuations with some good examples, that would be much appreciated as well.


Solution

  • As seen in the base case in the code, your collector/continuation must take 3 arguments. It seems you passed in a function which doesn't.


    It's good you worked through multirember&co: I wrote an answer about it, which you may wish to review.

    Anyway, a general approach in testing these collector/continuations is to start by using list as your continuation, since list is variadic and simply returns the items given as a list. Here's an example:

    > (multiinsertLR&co 'foo 'bar 'baz '(foo bar baz qux quux) list)
    '((foo foo bar baz foo qux quux) 1 1)
    

    Oh, I see two foos! Which one was inserted, and which one was in the original list?

    > (multiinsertLR&co 'foo 'bar 'baz '(goo bar baz qux quux) list)
    '((goo foo bar baz foo qux quux) 1 1)
    

    Ah, so we're on to something! Any time the list contains a bar, foo is inserted before it; and any time the list contains a baz, foo is inserted after it. But the numbers?

    > (multiinsertLR&co 'foo 'bar 'baz '(baz goo bar baz qux bar quux baz) list)
    '((baz foo goo foo bar baz foo qux foo bar quux baz foo) 2 3)
    

    Those numbers look like counters! Each "left" insertion increments the first counter, and each "right" insertion increments the second counter.


    In looking at the code, if you look at each of the branches of the cond, you will see what happens in a left-match case, a right-match case, and a not-match case (and of course, an end-of-list case, which sets up the base/initial value). Notice how the insertion (and counter increment) happens in each case. Since you already get multirember&co, this should be fairly easy from here on. All the best!