• No results found

Functions that Produce Lists

In document How to Design Programs (Page 151-156)

Recall the function wage from section 2.3:

;; wage : number -> number

;; to compute the total wage (at $12 per hour)

;; of someone who worked for h hours (define (wage h)

(* 12 h))

The wage function consumes the number of hours some employee worked and produces the weekly wage payment. For simplicity, we assume that all employees earn the same hourly rate, namely, $12. A company, however, isn't interested in a function like wage, which computes the wage of a single employee. Instead, it wants a function that computes the wages for all of its employees, especially if there are a lot of them.

Call this new function hours->wages. It consumes a list that represents how many hours the employees of the company worked and must produce a list of the weekly wages they earned. We can represent both the input and the output as Scheme lists of numbers. Since we already have a data definition for the inputs and outputs, we can immediately start our function development:

;; hours->wages : list-of-numbers -> list-of-numbers

;; to create a list of weekly wages from a list of weekly hours (alon)

(define (hours->wages alon) ...)

Next we need some examples of inputs and the corresponding outputs:

empty

The outputs are obtained by calculating the wage for each item on the list to the left.

Given that hours->wages consumes the same class of data as, say, the function sum, and given that the shape of a function template depends only on the shape of the data definition, we can reuse the list-of-numbers template:

(define (hours->wages alon) (cond

[(empty? alon) ...]

[else ... (first alon) ... (hours->wages (rest alon)) ...]))

Starting with this template, we can turn to the most creative step of function

development: the definition of the function body. Following our recipe, we consider each cond-line in isolation, starting with the simpler case. First, assume (empty? alon)

is true, which means that the input is empty. The answer in this case is empty:

(define (hours->wages alon)

(cond

[(empty? alon) empty]

[else ... (first alon) ... (hours->wages (rest alon)) ...]))

Second, assume that alon was constructed from a number and a list of numbers. The expressions in the second line remind us of this assumption, and the recipe tells us that we should state explicitly what they compute:

1. (first alon) yields the first number on alon, which is the first number of hours worked; and

2. (hours->wages (rest alon)) reminds us that (rest alon) is a list and can be processed by the very function we are defining. According to the purpose statement, the expression computes the list of wages for the rest of the list of hours, and we may assume this relationship in our construction -- even though the function is not yet completely defined.

From here it is a short step to the complete function definition. Since we already have the list of wages for all but the first item of alon, the function must do two things to produce an output for the entire list of hours:

1. Compute the weekly wage for the first number of hours.

2. Construct a list that represents all weekly wages for alon, using the first weekly wage and the list of weekly wages for (rest alon).

For the first part, we reuse wage. For the second, we cons the two pieces of information together into one list:

(cons (wage (first alon)) (hours->wages (rest alon)))

And with that, we have a complete function. It is shown in figure 27. To finish the design of the function, we must still test it.

;; hours->wages : list-of-numbers -> list-of-numbers

;; to create a list of weekly wages from a list of weekly hours (alon)

(define (hours->wages alon) (cond

[(empty? alon) empty]

[else (cons (wage (first alon)) (hours->wages (rest alon)))]))

;; wage : number -> number

;; to compute the total wage (at $12 per hour)

;; of someone who worked for h hours (define (wage h)

(* 12 h))

Figure 27: Computing weekly wages

Exercise 10.1.1. How do we have to change the function in figure 27 if we want to give everyone a raise to $14? Solution

Exercise 10.1.2. No employee could possibly work more than 100 hours per week. To protect the company against fraud, the function should check that no item of the input list of hours->wages exceeds 100. If one of them does, the function should immediately signal the error "too many hours".

How do we have to change the function in figure 27 if we want to perform this basic reality check? Solution

Exercise 10.1.3.

Develop convertFC. The function converts a list of Fahrenheit measurements to a list of Celsius measurements. Solution

Exercise 10.1.4. Develop the function convert-euro, which converts a list of U.S.

dollar amounts into a list of euro amounts. Assume the exchange rate is 1.22 euro for each dollar.

Generalize convert-euro to the function convert-euro-1, which consumes an exchange rate and a list of dollar amounts and converts the latter into a list of euro amounts. Solution

Exercise 10.1.5. Develop the function eliminate-exp to eliminate expensive toys.

The function consumes a number, called ua, and a list of toy prices, called lotp, and produces a list of all those prices in lotp that are below or equal to ua. For example,32

(eliminate-exp 1.0 (cons 2.95 (cons .95 (cons 1.0 (cons 5 empty)))))

;; expected value:

(cons .95 (cons 1.0 empty))

Solution

Exercise 10.1.6. Develop the function name-robot, which consumes a list of toy descriptions (names) and produces an equivalent list of more accurate descriptions.

Specifically, it replaces all occurrences of 'robot with 'r2d2 and otherwise retains the toy descriptions in the same order.

Generalize name-robot to the function substitute. The new function consumes two symbols, called new and old, and a list of symbols. It produces a new list of symbols by substituting all occurrences of old by new. For example,

(substitute 'Barbie 'doll (cons 'robot (cons 'doll (cons 'dress empty))))

;; expected value:

(cons 'robot (cons 'Barbie (cons 'dress empty)))

Solution

Exercise 10.1.7. Develop the function recall to eliminate specific toys from a list.

The function consumes the name of a toy, called ty, and a list of names, called lon, and produces a list of names that contains all components of lon with the exception of ty. For example,

(recall 'robot (cons 'robot (cons 'doll (cons 'dress empty))))

;; expected value:

(cons 'doll (cons 'dress empty))

Solution

Exercise 10.1.8. Develop quadratic-roots, which solves quadratic equations: see exercises 4.4.4 and 5.1.4. The function accepts the coefficients a, b, and c. The computations it performs depend on the input:

1. if a = 0, its output is 'degenerate.

2. if b2 < 4 · a · c, the quadratic equation has no solution; quadratic-roots

produces 'none in this case.

3. if b2 = 4 · a · c, the equation has one solution:

the solution is the answer.

4. if b2 > 4 · a · c, the equation has two solutions:

and

the result is a list of two numbers: the first solution followed by the second solution.

Test the function with the examples from exercises 4.4.4 and 5.1.4. First decide the answer for each example, then determine it with DrScheme. Solution

Exercise 10.1.9. The cash registers at many grocery stores talk to customers. The register's computer receives the number of cents that the customer must pay and then builds a list with the following five items:

1. the dollar amount;

2. the symbol 'dollar if the dollar amount is 1 and 'dollars otherwise;

3. the symbol 'and;

4. the cent amount; and

5. the symbol 'cent if the cent amount is 1 and 'cents otherwise.

Develop the function controller, which consumes a number and produces a list according to the above description. For example, if the amount is $1.03, then the cash register evaluates (controller 103):

(controller 103)

;; expected value:

(cons 1 (cons 'dollar (cons 'and (cons 3 (cons 'cents empty)))))

Hint: Scheme provides the arithmetic operations quotient and remainder, which produce the quotient and remainder of the expression n/m for integers n and m, respectively.

Sound Files

Once the controller returns the correct list for amounts whose dollar and cent amounts are between 0 and 20, test the controller with a computer that can speak. Set the teachpack to sound.ss, which makes two operations available: speak-word and

speak-list. The first accepts a symbol or a number, the second a list of symbols and numbers. Both pronounce the symbols they consume. Evaluate the following

expressions (speak-word 1), (speak-list (cons 1 (cons 'dollar empty))), and

(speak-list (cons 'beautiful (cons 'lady empty))) to understand how the operations operate.

Simple Challenge: The sound teachpack contains only the sounds for the numbers 0

through 20 and 30, 40, 50, 60, 70, 80, and 90. Because of this restriction, this challenge problem works only on amounts with cents and dollars between 0 to 20. Implement a controller that deals with arbitrary amounts between 0 and 99.99. Solution

10.2

In document How to Design Programs (Page 151-156)