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 '())) (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 '())) (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 '())) (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.
Design, write, and test 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 keys that
takes one argument, an association list, and returns a list of the keys in
that association list.
The map procedure can actually take more than two arguments,
if all of the extras are lists, and the arity of the procedure that map applies is increased to match:
> (map string-append '("left" "start" "beginning")
'("-to-" "-to-" "-to-")
'("right" "finish" "end"))
("left-to-right" "start-to-finish" "beginning-to-end")
> (map cons '(a b c) '(d e f))
((a . d) (b . e) (c . f))
Using map, define a procedure pairwise-sum that takes as
arguments two lists of numbers, equal in length, and returns a new list
whose components are the sums of the corresponding components of the
arguments.
Design, write, and test a procedure dot-product that takes as
arguments two lists of numbers, equal in length, and returns the sum of the
products of corresponding elements of the arguments. Here are two sample
calls:
> (dot-product '(1 2 4 8) '(11 5 7 3)) 73 ; ... because (1 x 11) + (2 x 5) + (4 x 7) + (8 x 3) = ; 11 + 10 + 28 + 24 = 73 > (dot-product '() '()) 0 ; ... because in this case there are no products to add
One can use apply and map to give an extremely concise
definition of this procedure.
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)
Design, write, and test 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.
I am indebted to Professor Ben Gum for his contributions to the development of this lab.