EXERCISE SET #3

1. Define a Scheme procedure quadratic that takes three arguments a, b, and c, all real numbers, and returns a list of the roots of the quadratic equation ax^2 + bx + c = 0.

(define quadratic-roots
  (lambda (a b c)
    (cond ((not (zero? a))
           (discard-duplicates (quadratic-formula a b c)))
          ((not (zero? b))
           (list (/ (- c) b)))
          ((not (zero? c))
           '())
          (else (display "all numbers are roots") (newline)))))

(define discard-duplicates
  (lambda (solutions)
    (if (= (car solutions)
           (cadr solutions))
        (cdr solutions)
        solutions)))

(define quadratic-formula
  (lambda (a b c)
    (list (/ (+ (- b) (discriminant a b c)) (* 2 a))
          (/ (- (- b) (discriminant a b c)) (* 2 a)))))

(define discriminant
  (lambda (a b c)
    (sqrt (- (square b) (* 4 a c)))))

(define square
  (lambda (n)
    (* n n)))
2. Define a Scheme procedure subst that takes three arguments (two arbitrary values and a list) and returns a list just like the given list except that every occurrence of the first value has been replaced with the second value. For instance, the value of the call (subst 'c 'k '(c o c o n u t)) should be (k o k o n u t).

(define subst
  (lambda (old new ls)
    (if (null? ls)
        '()
        (cons (if (equal? old (car ls))
                  new
                  (car ls))
              (subst old new (cdr ls))))))
3. Define a Scheme procedure list-segment that takes three arguments -- the first a list, the second a natural number no greater than the length of the list, and the third a natural number no less than the second argument but no greater than the length of the list -- and returns a segment of the given list, starting after the number of elements indicated by the second argument and stopping after the element indicated by the third argument. For instance, the value of the call (list-segment '(a b c d e f g) 3 5) should be (d e) -- the segment of (a b c d e f g) that starts after the third element and stops at the fifth. If the second and third elements are equal, list-segment should return the empty list.

(define list-segment
  (lambda (ls start stop)
    (if (zero? start)
        (list-segment-helper ls stop)
        (list-segment (cdr ls) (sub1 start) (sub1 stop)))))

(define list-segment-helper
  (lambda (ls stop)
    (if (zero? stop)
        '()
        (cons (car ls) (list-segment-helper (cdr ls) (sub1 stop))))))

(define sub1
  (lambda (n)
    (- n 1)))
4. Define a Scheme procedure range-sum that takes two integer arguments and finds the sum of all the integers greater than or equal to the first argument and less than or equal to the second. For instance, the value of the call (range-sum 12 16) should be 70 (that is, 12 + 13 + 14 + 15 + 16).

(define range-sum
  (lambda (start stop)
    (if (< stop start)
        0
        (+ start (range-sum (add1 start) stop)))))

(define add1
  (lambda (n)
    (+ n 1)))
5. Let's define a numeric structure, recursively, as a value that is either the null object, or a real number, or a pair of numeric structures. Define a Scheme procedure that finds the sum of all the real numbers that occur anywhere inside a given numeric structure.

(define sum-of-structure
  (lambda (struct)
    (cond ((null? struct) 0)
          ((real? struct) struct)
          ((pair? struct) (+ (sum-of-structure (car struct))
                             (sum-of-structure (cdr struct))))
          (else (error "sum-of-structure: argument not a numeric structure")))))
6. Define a Scheme procedure that finds that greatest real number in a given numeric structure. (If the structure contains no real numbers -- for instance, if it is the null object -- the procedure should return #f.)

(define greatest-of-structure
  (lambda (struct)
    (cond ((null? struct) #f)
          ((real? struct) struct)
          ((pair? struct)
           (greater-if-number (greatest-of-structure (car struct))
                              (greatest-of-structure (cdr struct))))
          (else (error "greatest-of-structure: argument not a numeric structure")))))

(define greater-if-number
  (lambda (val-1 val-2)
    (if val-1
        (if val-2
            (max val-1 val-2)
            val-1)
        val-2)))
7. Similarly, let's define a symbolic structure as a value that is either the null object, or a symbol, or a pair of symbolic structures. Define a Scheme procedure contents that takes any symbolic structure as its argument and returns a list of all the symbols that occur anywhere inside that symbolic structure.

(define contents
  (lambda (struct)
    (cond ((null? struct) '())
          ((symbol? struct) (list struct))
          ((pair? struct) (append (contents (car struct))
                                  (contents (cdr struct))))
          (else (error "contents: argument not a symbolic structure")))))
8. Here's an alternative definition of a symbolic structure: a value that is either a symbol or a list of symbolic structures. Is this definition equivalent to the one proposed in the preceding exercise? Will your definition of contents still work for symbolic structures in the new sense? If not, how would you revise it?

The proposed new definition is more restrictive than the one used in the preceding exercise, since, for instance, the pair (a . b) counts as a symbolic structure under the old definition but not under the new one (it is neither a symbol nor a list). But everything that is a symbolic structure under the new definition was already covered under the old definition. (Since a list of symbolic structures is either the null object or a pair with a symbolic structure in its left field and a list of symbolic structures in its right field, the proposition follows by mathematical induction on the length of the list.) It is not necessary to change the definition of contents.

9. Define a Scheme procedure sum that yields the result described in exercise 3.1 on page 81 of the text, but obtains that result by an iterative process (as described in section 4.5).

(define sum-it
  (lambda (ls)
    (sum-it-helper ls 0)))

(define sum-it-helper
  (lambda (ls acc)
    (if (null? ls)
        acc
        (sum-it-helper (cdr ls) (+ (car ls) acc)))))
10. Define the iota procedure (exercise set #2, number 7) so that it obtains its result by an iterative process.

(define iota-it
  (lambda (n)
    (iota-it-helper n '())))

(define iota-it-helper
  (lambda (n so-far)
    (if (zero? n)
        so-far
        (iota-it-helper (sub1 n) (cons (sub1 n) so-far)))))

created June 12, 1996
last revised June 12, 1996

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