ICS H21 • UC IRVINE • DAVID G. KAY • FALL 2009

Lab Assignment 4

This assignment is due at the end of lab on Friday, October 23.

Choose a partner for this assignment, someone you haven't worked with already.

(a) Do exercise 11.2.2. What they're asking for is a list of n pairs (each pair is a posn structure; each pair has the values i and f(i) where i starts at n and goes down by one each time until it reaches zero). Next do exercise 12.2.1 (just adapting the program in Figure 33).

Write the function in-ascending-order? as described below; you might use this in testing the results of a sorting program.

;; in-ascending-order?: list-of-numbers -> boolean
;; Return true if the list is empty or if each item <= all following items
(check-expect (in-ascending-order? empty) true)
(check-expect (in-ascending-order? (list 17)) true)
(check-expect (in-ascending-order? (list 12 14 16 18 20)) true)
(check-expect (in-ascending-order? (list 12 14 18 16 20)) false)

(Hint: A one-element list is always in ascending order; consider treating that case in a separate cond clause.)

Here's a question to think about: If we want to test the correctness of our sorting function, is it enough to have tests of the form (check-expect (in-ascending-order? (sort L)) true)? That is, if the results of our sorting function are sorted into ascending order, are we satisfied that our sorting function works correctly? (Put another way, can we think of a way to write sort so that its result always passes the in-ascending-order? test but the result is not correctly sorted?)

Collect your definitions for all these exercises into one Scheme file, make sure both partners' names are in a comment at the top, and submit it via Checkmate.

(b) At this point in the assignment, change your language level to Intermediate Student.

Copy the code for the restaurants program to your machine and run it to make sure it works properly in your environment.

After completing the task of reimplementing the collection, add one new feature to the program: c: Change prices for the dishes served. When the user types 'c', the program should ask the user for an amount (positive or negative) representing a percentage change in price (so that 100 would double a price and -50 would cut it in half). Then it should apply that price change to the prices for all the restaurants in the collection. [Here are some hints on how to approach this. Before reading further, you might want to think about how you'd do it. You might approach this byfirst writing a rrant-change-price function that takes a restaurant and a percentage change number, as above, and returns a restaurant that has all the same information, except that the price is changed appropriately. Next you might write a function to apply rrant-change-price to all the restaurants in the collection. Finally, you can incorporate these calls into the main program, adding the appropriate command handling and so on.]

(c) As we start this part of the lab, we need to explain one new feature of Scheme: the quote operator. If we type (+ 2 2) in the interactions window, Scheme evaluates it by applying the + operator to its arguments to get 4. If we type "(+ 2 2)", scheme doesn't evaluate it as an arithmetic expression; the quotation marks just say to evaluate it as a string, and return the literal value "(+ 2 2)". Sometimes we want Scheme to evaluate what we type; sometimes we just want Scheme to treat it as data. The way we say "don't evaluate" in Scheme is not to use double quote marks (which actually say "evaluate this as a string"). Instead, we use the quote operator, which can take the form (quote x) or 'x. This is particularly convenient if we want to indicate a constant list in our code: We can still say (list 1 2 3), but we can also say (quote (1 2 3)) or '(1 2 3). Of course (1 2 3) (without the list or quote or apostrophe) would give us an error, because 1 isn't the name of a defined function. In this lab problem, you can see how we mght want to use quoted lists.

A recipe is a structure

    (make-recipe T IL SL)
where T is the title (a symbol), IL is a list of ingredients, and SL is a list of steps.

An single ingredient is a symbol (like 'eggs); a single step is a list of symbols (like '(beat the eggs)). A recipe contains a list of ingredients and a list of steps; for example:

(make-recipe 'ThaiIcedCoffee 
     '(coffee sugar condensed-milk ice) 
     '((brew coffee) (add sugar and condensed-milk) (pour coffee mixture over ice)))

(Here you can see one advantage of using symbols instead of strings; with strings, we'd have to double-quote every individual word, but with symbols, we can just single-quote the whole list of them. Ask yourselves: What would be the problem with double-quoting the whole list of symbols here?)

(c.1) Write the structure definition for a recipe, using "title," "ingredients," and "steps" as the names of the fields.

(c.2) Some people say that any recipe can be improved by the addition of chocolate. (Others say sesame oil, or Tabasco sauce.) Write a definition of add-special-ingredient. You may use an auxiliary function if you like.

; add-special-ingredient:  list-of-recipes  symbol   ->  list-of-recipes 
; Return a list containing all the recipes in the input list, but with the symbol added
;      at the beginning of the ingredients list of each recipe.

(c.3) Write a definition for complete-ingredients-list .

; complete-ingredients-list:  list-of-recipes  ->  list-of-symbols
; Return a list containing all the ingredients from all the recipes in the list,
;     with no duplications.  (You may assume that all the elements of a single
;     ingredients list are unique.)

[Hint: Define an auxiliary function called add-unique.]

(c.4) Sometimes we have to substitute one ingredient for another in a recipe. Write a definition for replace-ingredient as described below. Auxiliary functions are essential here.

; replace-ingredient: symbol1  symbol2  recipe  ->  recipe 
; Return a recipe like the input, but with every instance of symbol1 replaced by symbol2, 
;     both in the ingredients list and in the list of steps. 
; Example: Suppose TIC is the Thai Iced Coffee recipe defined above. 
;    (replace-ingredient 'coffee 'decaf  TIC) would return 
;    (make-recipe 'ThaiIcedCoffee 
;        '(decaf sugar condensed-milk ice)
;        '((brew decaf) (add sugar and condensed-milk) (pour decaf mixture over ice)))

(c.5) Some recipes are so complex that they include in their steps some references to other recipes. A cake recipe in a cookbook, for example, might have as one step, "Use the chocolate icing recipe on page 23." To reflect this in our Scheme recipes, we change our definition of a "list of steps":

A list of steps (LOS) is either

  1. empty;
  2. (cons S LOS), where S is a single step (i.e., a list of symbols); or
  3. (cons R LOS), where R is a recipe.

Write a definition for complete-ingredients-list2 that accommodates these (possibly nested) recipes.

; complete-ingredients-list2:  list-of-recipes ->  list-of-symbols 
; Return a list containing all the ingredients from all the recipes in the list, 
;     including nested recipes, with no duplications.  (You may assume that all the
;     elements of a single ingredients list are unique.)  

Collect these definitions and submit them via Checkmate. Turn in what you have by the due date; then consult with the TA if you'd like to keep working.

(d) (extra credit, according to the usual rules) Do exercises 12.4.1 and 12.4.2.

(e) Remember that each partner must complete a partner evaluation form via the Survey tool on eee.uci.edu.


Based in part on ICS H21assignments by David G. Kay from Fall 2001; modified by David G. Kay, Fall 2004–Fall 2009.


David G. Kay, kay@uci.edu
Sunday, October 18, 2009 4:53 PM