Solutions for exercise set #3

1. Procedures as values.

;; The ACCUMULATE procedure takes three arguments -- a procedure PROC of
;; arity 2, an initial value START, and a list LS -- and returns the result
;; of applying PROC first to the initial value and the first element of the
;; list, then to the result of the first step and the second element of the
;; list, then to the result of the second step and the third element of the
;; list, and so on.  If LS is the null list, ACCUMULATE returns the initial
;; value unchanged.

(define accumulate
  (lambda (proc start ls)

    ;; Test the preconditions.

    (if (not (procedure? proc))
        (error 'accumulate "The first argument must be a procedure"))
    (if (not (list? ls))
        (error 'accumulate "The third argument must be a list"))

    ;; Loop until the list is empty; at each stage, the new value of
    ;; SO-FAR is the result of applying PROC to the old value and the
    ;; first remaining element of the list.

    (let loop ((so-far start)
               (rest ls))
      (if (null? rest)
          so-far
          (loop (proc so-far (car rest)) (cdr rest))))))

2. A variation on map.

;; The VARIANT-MAP procedure takes two arguments, of which the first must
;; be a list LS of procedures of arity 1, and returns a list whose elements
;; are the results of applying the members of LS to the second argument to
;; VARIANT-MAP.

(define variant-map
  (lambda (procs arg)

    ;; Test the precondition.

    (if (not ((list-of procedure?) procs))
        (error 'variant-map
               "The first argument must be a list of procedures"))

    ;; Use MAP to run down the list PROCS, applying each element to ARG.

    (map (lambda (proc) (proc arg)) procs)))

;; The LIST-OF procedure takes as argument a predicate PRED? of arity 1 and
;; returns a predicate that determines whether its argument is a list, all
;; of the elements of which satisfy PRED?.

(define list-of
  (lambda (pred?)
    (letrec ((test-all (lambda (obj)
                          (or (null? obj)
                              (and (pair? obj)
                              (pred? (car obj))
                              (test-all (cdr obj)))))))
      test-all)))

3. Returning procedures.

;; The procedure ITERATE takes two arguments, a natural number N and a
;; procedure F, and returns a procedure that is the Nth iterate of F --
;; in other words, a procedure that applies F to its argument, and then
;; applies F to the result of the first application, and then applies F
;; again to the result of the second application, and so on until F has
;; been applied N times.  If N is 0, ITERATE returns the identity
;; procedure -- the procedure that always returns its argument unchanged.

(define iterate
  (lambda (n f)

    ;; Test the preconditions.

    (if (or (not (integer? n))
            (negative? n))
        (error 'iterate "The first argument must be a natural number"))
    (if (not (procedure? f))
        (error 'iterate "The second argument must be a procedure"))

    ;; Start with the identity procedure.

    (let loop ((so-far (lambda (x) x))
               (remaining n))

      ;; When the count of remaining iterations is reduced to zero,
      ;; return SO-FAR.

      (if (zero? remaining)
          so-far

          ;; If it is not yet zero, however, compose F with SO-FAR
          ;; once to get the next iterate and subtract one from the
          ;; count of remaining iterations.

          (loop (compose f so-far) (- remaining 1))))))

;; The COMPOSE procedure takes as arguments two procedures, F and G, each
;; of arity 1, and returns a procedure of arity 1 that returns the result
;; of first applying G to its argument and then applying F to the result of
;; that first application.

(define compose
  (lambda (f g)

    ;; Test the preconditions.

    (if (or (not (procedure? f))
            (not (procedure? g)))
        (error 'compose "Both arguments must be procedures"))

    ;; Return a procedure that applies G and then F.

    (lambda (x)
      (f (g x)))))

This document is available on the World Wide Web as

http://www.math.grin.edu/courses/Scheme/solutions-3.html

created April 13, 1997
last revised May 28, 1997
John David Stone (stone@math.grin.edu)