Exercise #10

Many Scheme procedures (including standard procedures like member and assoc) perform operations that can either ``succeed,'' returning some useful value, or ``fail,'' returning #f.

For instance, here is a procedure that looks for a given value inside a given vector. If the search is successful, the procedure returns the position at which the value was discovered; otherwise, the procedure returns #f.

;;; The FIND-IN-VECTOR procedure searches through a given vector, from left
;;; to right, looking for an element that is equal to a given value.  If it
;;; finds such an element, it returns the position of that element in the
;;; vector; if not, it returns #F.

(define (find-in-vector vec item-sought)
  (let ((len (vector-length vec)))
    (let loop ((position 0))
      (cond ((= position len) #f)
            ((equal? (vector-ref vec position) item-sought) position)
            (else (loop (+ position 1)))))))

It is sometimes awkward to work with such procedures in Scheme because of the two-step process of decoding the output. Suppose, for instance, that we want to write an expression that displays either the result of a call to find-in-vector, appropriately labelled, or a report that the search failed. It is natural to try to write something like this:

(if (find-in-vector vec item-sought)
    (printf "I found the item in position ~a.~%"
            (find-in-vector vec item-sought))
    (printf "I didn't find the item.~%"))

However, this approach involves repeating the call to find-in-vector whenever it succeeds, which is inefficient. (Duplicating expressions is also bad programming style, since if the repeated expression happens to contain an error or needs to be modified when a program is revised or updated, it is all too easy to forget to correct or modify all of the copies.)

One can avoid the code duplication by writing

(let ((search-result (find-in-vector vec item-sought)))
  (if search-result
      (printf "I found the item in position ~a.~%" search-result)
      (printf "I didn't find the item.~%")))

But this seems a little cumbersome for such a simple idea, and it calls attention to the awkwardness of having search-result be sometimes a Boolean and sometimes a number that is treated as ``truish.''

Using ``wish-list'' programming, one might wish that Scheme supported a more natural syntax for this construction -- perhaps something like this:

(provided index from (find-in-vector vec item-sought)
  (printf "I found the item in position ~a.~%" index)
  (printf "I didn't find the item.~%"))

Here provided and from are keywords -- unvarying syntactic markers. A provided-expression first evaluates the expression following from and stores the result in a storage location bound to the identifier that appears between provided and from. The remaining two expressions are treated as a consequent and an alternate: If the value of the expression following from is truish (that is, anything except #f), then the consequent is evaluated, and its value is the value of the whole provided-expression; otherwise, the alternate is evaluated, and its value is the value of the whole provided-expression.

Write and test a syntax definition that introduces provided-expressions into standard Scheme.

This exercise is optional. I will award extra credit for any correct answers that I receive, but there is no penalty for not submitting a solution. This exercise will be due at 9 a.m. on Wednesday, May 5.


This document is available on the World Wide Web as

http://www.cs.grinnell.edu/~stone/courses/scheme/exercises/10.xhtml

Validated as XHTML 1.1 by the World Wide Web Consortium Cascading Style Sheet validated by the World Wide Web Consortium

created April 28, 2004
last revised June 3, 2004

John David Stone (stone@cs.grinnell.edu)