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
created April 28, 2004
last revised June 3, 2004