Here are three procedures with similar structures:
;;; whitespace-tally: determine how many elements of a given
;;; list of characters are whitespace characters
;;; Given:
;;; LS, a list of characters.
;;; Result:
;;; TALLY, an integer.
;;; Preconditions:
;;; None.
;;; Postcondition:
;;; TALLY is the number of elements of LS that are
;;; whitespace characters.
(define whitespace-tally
(lambda (ls)
(cond ((null? ls) 0)
((char-whitespace? (car ls))
(+ (whitespace-tally (cdr ls)) 1))
(else (whitespace-tally (cdr ls))))))
;;; even-tally: determine how many elements of a given list
;;; of exact integers are even
;;; Given:
;;; LS, a list of exact integers.
;;; Result:
;;; TALLY, an integer.
;;; Preconditions:
;;; None.
;;; Postcondition:
;;; TALLY is the number of even elements of LS.
(define even-tally
(lambda (ls)
(cond ((null? ls) 0)
((even? (car ls)) (+ (even-tally (cdr ls)) 1))
(else (even-tally (cdr ls))))))
;;; symbol-tally: determine how many elements of a given
;;; list are symbols
;;; Given:
;;; LS, a list.
;;; Result:
;;; TALLY, an integer.
;;; Preconditions:
;;; None.
;;; Postcondition:
;;; TALLY is the number of elements of LS that are symbols.
(define symbol-tally
(lambda (ls)
(cond ((null? ls) 0)
((symbol? (car ls)) (+ (symbol-tally (cdr ls)) 1))
(else (symbol-tally (cdr ls))))))
By abstracting what these procedures have in common, develop a procedure
tallier that takes a predicate as its argument and constructs
and returns a specialized tallying procedure that counts the number of
elements of a given list that satisfy the predicate.
How would you use the tallier procedure that you defined in
exercise 1 to create procedures to determine
'n/a (``not
available'') in a list? (Hint: Use a lambda-expression.)Here are three procedures, each of which takes a natural number as argument and returns a list:
;;; generate-list-of-squares: construct and return a list of
;;; the squares of natural numbers less than a given natural
;;; number
;;; Given:
;;; LEN, an integer.
;;; Result:
;;; LS, a list.
;;; Precondition:
;;; LEN is exact and not negative.
;;; Postconditions:
;;; (1) The length of LS is LEN.
;;; (2) For every natural number k less than LEN, the element
;;; at position k of LS is the square of k.
(define generate-list-of-squares
(lambda (len)
(let kernel ((remaining len)
(so-far null))
(if (zero? remaining)
so-far
(let ((next (- remaining 1)))
(kernel next (cons (* next next) so-far)))))))
;;; generate-list-of-hyphen-strings: construct and return
;;; a list of strings of hyphens of length less than
;;; a given natural number.
;;; Given:
;;; LEN, an integer.
;;; Result:
;;; LS, a list.
;;; Precondition:
;;; LEN is exact and not negative.
;;; Postconditions:
;;; (1) The length of LS is LEN.
;;; (2) For every natural number k less than LEN, the element
;;; at position k of LS is the a string of hyphens of length
;;; k.
(define generate-list-of-hyphen-strings
(lambda (len)
(let kernel ((remaining len)
(so-far null))
(if (zero? remaining)
so-far
(let ((next (- remaining 1)))
(kernel next (cons (make-string next #\-) so-far)))))))
;;; generate-list-of-termials: construct and return a list of
;;; the ``termials'' of natural numbers less than a given
;;; natural number
;;; Given:
;;; LEN, an integer.
;;; Result:
;;; LS, a list.
;;; Precondition:
;;; LEN is exact and not negative.
;;; Postconditions:
;;; (1) The length of LS is LEN.
;;; (2) For every natural number k less than LEN, the element
;;; at position k of LS is the sum of the natural numbers
;;; less than or equal to k.
(define generate-list-of-termials
(lambda (len)
(let kernel ((remaining len)
(so-far null))
(if (zero? remaining)
so-far
(let ((next (- remaining 1)))
(kernel next (cons (termial next) so-far)))))))
(The termial
procedure was defined in the reading on recursion with integers; it
computes the sum of all the natural numbers up to and including its
argument.)
Apply each of these procedures to a few small natural numbers to see what they do.
Develop a generate-list procedure that abstracts the common
structure of these three definitions. Generate-list should
take, as its argument, any one-argument procedure procedure
that can be applied to a natural number. Generate-list should
return, as its value, a procedure that, when applied to a natural number
len, constructs and returns a list of the results of applying
procedure to every natural number less than len.
Use map to give a concise definition of a procedure
association-list-keys that takes one argument, an association list, and returns a list of
the keys in that association list.
Use map to write a version of
square-each-element described in the recursion with lists lab, which
returns a list of the squares of the numbers in the original list.
Use apply to give an extremely concise
definition of the procedure sum, which returns the sum of a
list of numbers.
Develop the higher-order procedure right-section, which takes
a procedure of two arguments and a value to drop in as its second
argument, and returns the operator section that expects the first
argument. (For instance, (right-section expt 3) is a
procedure that computes the cube of any number it is given.) You can use
the definition of left-section as a model.
Using the generate-list procedure from exercise 3, above, and
an operator section, define a procedure powers-of-two that
constructs and returns a list of powers of two, in ascending order, given
the length of the desired list. Here's a sample call:
> (powers-of-two 7)
(1 2 4 8 16 32 64)
Define a procedure bounded-mu that takes two arguments, a
predicate predicate and a natural number limit,
and returns the least natural number less than limit that
satisfies predicate, or #f if there is no such
number.
Use bounded-mu to find the least natural number less than 1000
that leaves a remainder of 5 when divided by 7, a remainder of 7 when
divided by 11, and a remainder of 11 when divided by 13.
Define the intersection procedure (from exercise 6 in the
lab on local binding and recursion) using the remove
procedure presented in today's reading and the right-section
procedure developed in exercise 7 above.
The filters constructed by remove are designed to
exclude list elements that satisfy a given predicate. Define a
higher-order procedure filter that returns a filtering
procedure that retains the elements that satisfy a given predicate
(excluding those that fail to satisfy it). For instance, applying
the filter (filter even?) to a list of integers should return
a list consisting of just the even elements of the given list.
This document is available on the World Wide Web as
http://www.cs.grinnell.edu/~stone/courses/scheme/labs/procedures-as-values.xhtml
created March 24, 1997
last revised October 8, 2002
John David Stone (stone@cs.grinnell.edu) and Ben Gum (gum@cs.grinnell.edu)