SOLUTIONS FOR EXERCISE SET #5

1. Define a Scheme procedure that computes and returns the standard deviation of any non-empty list of real numbers.

(define standard-deviation
  (lambda (ls)
    (let* ((n (length ls))
           (mu (/ (sum ls) n)))
      (sqrt (/ (let loop ((rest ls)
                          (total 0.0))
                 (if (null? rest)
                     total
                     (loop (cdr rest)
                           (+ total (square (- (car rest) mu))))))
               n)))))

(define sum
  (lambda (ls)
    (let sum-it ((rest ls)
                 (total 0.0))
      (if (null? rest)
          total
          (sum-it (cdr rest) (+ total (car rest)))))))

(define square
  (lambda (n)
    (* n n)))
2. Define a Scheme procedure that takes two lists of symbols, equal in length, and determines the number of positions at which they contain different values. For instance, given the lists (a b c e f g) and (a b d e g h), the procedure should return 3. Use a named let-expression as the body of the procedure and ensure that it computes the result by an iterative process.

(define differ
  (lambda (list-1 list-2)
    (let differ-it ((rest-1 list-1)
                    (rest-2 list-2)
                    (tally 0))
      (if (null? rest-1)
          tally
          (differ-it (cdr rest-1)
                     (cdr rest-2)
                     (if (eq? (car rest-1) (car rest-2))
                         tally
                         (+ tally 1)))))))
3. Let's dress up the preceding exercise a little by making it a component of an experiment in short-term memory. Suppose that the symbols in the first list are random letters or nonsense syllables that the subject is supposed to memorize during a short exposure, and those in the second list are the subject's report of what she remembers from that exposure. The Scheme procedure is supposed to evaluate how well the response was remembered.

For this purpose, the Scheme procedure defined in exercise 2 does a poor job, since it imposes just as great a penalty for mispositioning a symbol as for forgetting it entirely and substituting a completely different symbol. The exercise is to propose a better scoring method and to implement it as a Scheme procedure.

The following procedure awards one point for each symbol that the subject provides anywhere in her list, but subtracts a small penalty if it is in the incorrect position, counting from the front of the list. (The penalty is the distance between the guessed position of the symbol and its correct position, divided by the full length of the list.)

(define score
  (lambda (correct guessed)
    (let score-it ((rest-correct correct)
                   (rest-guessed guessed)
                   (right 0)
                   (inversions 0))
      (cond ((or (null? rest-correct)
                 (null? rest-guessed))
             (- right (/ inversions (length correct))))
            ((member? (car rest-correct) rest-guessed)
             (score-it (cdr rest-correct)
                       (remove-1st (car rest-correct) rest-guessed)
                       (+ right 1)
                       (+ inversions (index (car rest-correct) rest-guessed))))
            ((member? (car rest-guessed) rest-correct)
             (score-it (remove-1st (car rest-guessed) rest-correct)
                       (cdr rest-guessed)
                       (+ right 1)
                       (+ inversions (index (car rest-guessed) rest-correct))))
            (else
             (score-it (cdr rest-correct)
                       (cdr rest-guessed)
                       right
                       inversions))))))

(define member?
  (lambda (obj ls)
    (and (not (null? ls))
         (or (eq? obj (car ls))
             (member? obj (cdr ls))))))

(define remove-1st
  (lambda (obj ls)
    (let loop ((rest ls)
               (so-far '()))
      (cond ((null? rest) (reverse so-far))
            ((eq? obj (car rest)) (append (reverse so-far) (cdr rest)))
            (else (loop (cdr rest) (cons (car rest) so-far)))))))

(define index
  (lambda (obj ls)
    (let loop ((rest ls)
               (so-far 0))
      (cond ((null? rest) #f)
            ((eq? obj (car rest)) so-far)
            (else (loop (cdr rest) (+ so-far 1)))))))
4. Define a Scheme procedure shuffle that takes two lists as arguments and returns a single list, the elements of which are drawn alternately from the two given lists as long as they both hold out, after which the rest of the elements are the same as those of the longer of the given lists. For instance, the value of the call (shuffle '(a b c d e) '(x y z)) is (a x b y c z d e).

(define shuffle
  (lambda (list-1 list-2)
    (let shuffle-it ((rest-1 list-1)
                     (rest-2 list-2)
                     (shuffled '()))
      (cond ((null? rest-1)
             (append (reverse shuffled) rest-2))
            ((null? rest-2)
             (append (reverse shuffled) rest-1))
            (else (shuffle-it (cdr rest-1)
                              (cdr rest-2)
                              (cons (car rest-2)
                                    (cons (car rest-1) shuffled))))))))
5. Define a Scheme procedure merge that takes two lists of real numbers, both in ascending order, and returns a single list, containing all the elements from both lists, also in ascending order.

(define merge
  (lambda (list-1 list-2)
    (let merge-it ((rest-1 list-1)
                   (rest-2 list-2)
                   (merged '()))
      (cond ((null? rest-1)
             (append (reverse merged) rest-2))
            ((null? rest-2)
             (append (reverse merged) rest-1))
            ((< (car rest-1) (car rest-2))
             (merge-it (cdr rest-1)
                       rest-2
                       (cons (car rest-1) merged)))
            (else
             (merge-it rest-1
                       (cdr rest-2)
                       (cons (car rest-2) merged)))))))
6. Suppose we represent a playing card as a pair in which the left field is one of the four symbols spade, heart, diamond, club and the right field is an integer in the range from 1 (= ace) to 13 (= king). Define a Scheme predicate that determines whether a given list of five cards, considered as a poker hand, is a flush (that is, whether they are all of the same suit). Extend the exercise, if you like, to include predicates that test for other holdings.

(define flush?
  (lambda (poker-hand)
    (alike? car poker-hand)))

(define alike?
  (lambda (op ls)
    (or (null? ls)
        (null? (cdr ls))
        (let loop ((first (car ls))
                   (second (cadr ls))
                   (rest (cddr ls)))
          (and (eq? (op first) (op second))
               (or (null? rest)
                   (loop second (car rest) (cdr rest))))))))
7. Using the random procedure in SLIB or in your preferred Scheme implementation, define a Scheme procedure of arity zero that constructs and returns a randomly dealt five-card poker hand. (It's a little harder than it may look, since you can't construct each card independently. If your procedure deals out a hand with two aces of spades in it, it will be shot.)

8. The setting this time involves a word game in which each letter has a particular numerical value:

                  a, e, i, l, n, o, r, s, t, u:  1 point
                                          d, g:  2 points
                                    b, c, m, p:  3 points
                                 f, h, v, w, y:  4 points
                                             k:  5 points
                                          j, x:  8 points
                                          q, z: 10 points
Define a Scheme procedure that takes any word and determines the total of the values of its letters. (This is pretty easy if you represent a word as a list of letters, so for a little more of a challenge you might want to take this opportunity to become familiar with Scheme's string and character types by supposing that the argument will be presented as a string.)

(define word-score
  (lambda (word)
    (let loop ((remaining (string-length word))
               (score 0))
      (if (zero? remaining)
          score
          (let ((position (- remaining 1)))
            (loop position
                  (+ score
                     (letter-score (string-ref word position)))))))))

(define letter-score
  (lambda (letter)
    (case letter
      ((#\a #\e #\i #\l #\n #\o #\r #\s #\t #\u
        #\A #\E #\I #\L #\N #\O #\R #\S #\T #\U)  1)
      ((#\d #\g #\D #\G)                          2)
      ((#\b #\c #\m #\p #\B #\C #\M #\P)          3)
      ((#\f #\h #\v #\w #\y #\F #\H #\V #\W #\Y)  4)
      ((#\k #\K)                                  5)
      ((#\j #\x #\J #\X)                          8)
      ((#\q #\z #\Q #\Z)                         10)
      (else                                       0))))
9. Define a Scheme procedure that takes a list of pairs, each pair consisting of a symbol (either male or female) and a real number (representing a subject's reaction time on a particular task), and returns a list of two pairs, one consisting of the symbol male and the mean reaction time of all the male subjects, the other consisting of the symbol female and the mean reaction time of all the female subjects. If the given list of pairs contains no data for a sex, the corresponding entry in the result should have the symbol no-data in its right field instead of a number.

(define means-by-sex
  (lambda (data)
    (let loop ((rest data)
               (male-sum 0.0)
               (female-sum 0.0)
               (male-tally 0)
               (female-tally 0))
      (cond ((null? rest)
             (list (cons 'male
                          (if (zero? male-tally)
                              'no-data
                              (/ male-sum male-tally)))
                    (cons 'female
                          (if (zero? female-tally)
                              'no-data
                              (/ female-sum female-tally)))))
            ((eq? (caar rest) 'male)
             (loop (cdr rest)
                   (+ male-sum (cdar rest))
                   female-sum
                   (+ male-tally 1)
                   female-tally))
            ((eq? (caar rest) 'female)
             (loop (cdr rest)
                   male-sum
                   (+ female-sum (cdar rest))
                   male-tally
                   (+ female-tally 1)))))))
10. Suppose we represent a point in the Cartesian plane by a pair of real numbers, the car representing the point's x-coordinate and the cdr its y coordinate. Suppose further that we represent a line segment by a pair of which the two fields are the two endpoints of the segment.

Define a Scheme predicate that takes two line segments, one horizontal (i.e., both of its endpoints have the same y-coordinate) and the other vertical, and determines whether they intersect (that is, whether they have at least one point in common).

(define intersecting?
  (lambda (horizontal vertical)
    (and (or (<= (caar horizontal)
                 (caar vertical)
                 (cadr horizontal))
             (<= (cadr horizontal)
                 (caar vertical)
                 (caar horizontal)))
         (or (<= (cdar vertical)
                 (cdar horizontal)
                 (cddr vertical))
             (<= (cddr vertical)
                 (cdar horizonal))))))

created June 13, 1996
last revised June 18, 1996

John David Stone (stone@math.grin.edu)