Search code examples
schemeracketvariadic-functionssicp

How do you use dotted-tail notation correctly in this algorithm?


I'm doing the exercises from SICP (not homework) and exercise 2.20 introduces dotted-tail notation, which is where you use (define (f a . b) ...) to pass a variable number of arguments (which end up in a list b). This problem in particular wants a procedure which takes an integer a and returns a list of all arguments with parity equal to a's. The problem is not difficult; here is my solution:

(define (same-parity a . b); a is an int, b is any number of int arguments
  (let ((parity (remainder a 2)))
    (define (proc li)
      (cond ((null? li) null)
            ; If parity of the head of the list is = parity of a,
            ((= (remainder (car li) 2) parity)
             ; keep it and check the rest of the list.
             (cons (car li) (proc (cdr li))))
            ; Otherwise ignore it and check the rest of the list.
            (else (proc (cdr li)))))
    (cons a (proc b))))

My question is that I don't seem to be using the dotted-tail feature at all. I might as well have just accepted exactly two arguments, a number and a list; I'm effectively wrapping the algorithm in a procedure proc which does away with the dotted-tail thing.

Before I wrote this solution, I wanted to have a recursive call resembling

(same-parity a . (cdr b))

or something spiritually similar, but no matter how I tried it, I kept passing lists of lists or extra procedures or whatever. This could be because I don't know exactly what . does, only what I want it to do (the Racket docs didn't clear anything up either). To sum up,

Is my solution what was intended for this exercise, or is there a way to actually use the dot notation (which seems to be the point of the exercise) in the algorithm?


Solution

  • You can't use (same-parity a . (cdr b)) (since that would be read in as (same-parity a cdr b)), but you can use (apply same-parity a (cdr b)). That's how you "splat" a list into arguments.

    However, the "inner procedure" approach you had is generally more efficient, as there is less list copying going on.