Curriculum Builder Portal 2/11/10 9:26 AM

total day span:"99" . 1 Get oriented to the UC-WISE system 2009-8-27 ~ 2009-8-28 (1 activity) 1.1 A brief introduction to UC-WISE(4 steps) 1.1.1 (Display page) Overview The UC-WISE system that you'll use in CS 3 this semester lets us organize activities that you'll be doing inside and outside class. Notice the sidebar on the left; it organizes the activities that you'll do during class. Two important activities are "brainstorming" and online discussion. You'll get practice with this now. 1.1.2 (Brainstorm) Brainstorming What's your favorite restaurant in Berkeley? 1.1.3 (Discussion Forum) Online discussion Explain what's so good about the restaurant(s) you mentioned in the previous step, and comment on one of the opinions of your classmates. 1.1.4 (Display page) The "extra brain" In the upper right part of the sidebar, there's an icon that's intended to resemble a brain. This is your "extra brain", where you can collect tips, things to remember, interesting programming examples, or anything else you'd like to keep track of in this course. Click on the brain icon and put a comment about a Berkeley restaurant you might want to try in it. Then click on the icon that looks like a diskette to save your brain entry. 2 Communicating with the Scheme interpreter 2009-8-27 ~ 2009-8-28 (7 activities) 2.1 Start "conversing" with the Scheme interpreter.(3 steps) 2.1.1 (Display page) Here is some information about the Scheme interpreter You will be using a programming language named Scheme for all your work in this course. The Scheme "interpreter" is a program that you will engage in "conversations". In this activity, you will experiment with typing things to the Scheme interpreter and observing how it responds. Some responses will seem reasonable. Others will be error messages that indicate that Scheme doesn't understand what you typed. Others will seem like nonsense. The easiest way to access Scheme is by running the stk program from a Unix terminal. From within Unix, type stk:

h30 [1] ~ > stk Welcome to the STk interpreter version 4.0.1-ucb1.16 [SunOS-5.9-sun4] Copyright (c) 1993-1999 Erick Gallesio - I3S - CNRS / ESSI Modifications by UCB EECS Instructional Support Group Questions, comments, or bug reports to . STk>

At the STk> prompt, you can now type something to the Scheme interpreter. The second way to run the scheme interpreter is to do so from within the emacs editor. We will explore this in more detail later, but when you are editing a Scheme file (a file with the .scm extension), emacs will present a "Scheme" menu with menu items that can access stk and send it commands. 2.1.2 (Display page) Start *conversing* with Scheme. With the person sitting next to you, experiment with the Scheme interpreter by typing words and numbers to it, one per line. Do this until together you have collected the following responses:

unbound variable bad syntax #[closure arglist= as well as the response that simply echoes what you typed in. 2.1.3 (Display page) Scheme *evaluates* your input. The process used by the Scheme interpreter to "understand" what you type is called evaluation. Scheme evaluates what you type, prints the resulting value, and waits for you to type some more. Scheme understands more than just numbers and a few symbols. The symbols to which Scheme responded with "#[closure arglist=args 1dec90]" or "#[subr and]" are names of procedures that you may use to produce more complicated results. We will study some of those now, in particular the procedures that correspond to elementary arithmetic operations. 2.2 Have some complicated "conversations".(7 steps) 2.2.1 (Display page) Start using builtin Scheme procedures. The Scheme interpreter knows about arithmetic operators, including + (plus), – (minus), and * (times). However, the way it wants you to specify an addition or subtraction differs from how we do it in English. In Scheme, you type a left parenthesis, then an arithmetic operator, then the operands, then a right parenthesis. Here are some examples. English Scheme 3 + 5 (+ 3 5) 3 – 5 (– 3 5) Adding or multiplying more than two numbers can be done in a sort of shorthand: English Scheme 3 + 5 + 4 (+ 3 5 4) 3 * 5 * 2 (* 3 5 2) The operands we supply to * or + are called inputs or arguments. The parenthesized uses of + and * are called expressions. For example, suppose you type the expression (+ 3 5 4). This is a request to evaluate the expression by adding the three inputs 3, 5, and 4. The value, or result of evaluation, is 12. 2.2.2 (Display page) Experiment with expressions. Continue experimenting with the Scheme interpreter. Note in particular that when you type a right parenthesis, the interpreter highlights the corresponding left parenthesis. This helps you detect missing parentheses. Find out three more things.

What happens when you type more than one expression on a line? In English, you can write 3+5, without blanks. How do you think the Scheme interpreter understands (+3 5) (with no space after the +)? What results from providing no inputs to +? Is this reasonable behavior?

Explain your answers to the person sitting next to you. 2.2.3 (Display page) Use arithmetic operators in combination. Type the Scheme equivalent of each of the following arithmetic expressions into the interpreter. If you get any of them wrong, add an entry to your Extra Brain explaining why. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 1 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

3 + (7-2) 3 + 4 * 5 (3 + 4) * 5 2.2.4 (Display page) Evaluation is inside-out. Evaluation in Scheme is inside-out. That is, it looks for an innermost parenthesized expression, and evaluates that, then repeats the process. For example, evaluation of the expression

(+ (* 5 2) (- 7 4))

might proceed by evaluating (* 5 2) and getting 10, then evaluating (- 7 4) and getting 3, then evaluating (+ 10 3) to get 13. 2.2.5 (Evidence) Here's a visual way to view procedures. The Simply Scheme textbook describes a visual way of viewing Scheme procedures. Click here to get a detailed explanation of this representation. 2.2.6 (Brainstorm) Why no parentheses in some arithmetic expressions? Parentheses weren't needed for the arithmetic expression 3 + 4 * 5, but they were needed for the equivalent Scheme expression. Explain why parentheses aren't needed for 3 + 4 * 5 in conventional arithmetic notation. 2.2.7 (Brainstorm) Explain how Scheme subtraction works. Figure out what Scheme evaluates a subtraction with more than two inputs, for example, (- 7 2 3 8). 2.3 Make your own procedures!(10 steps) 2.3.1 (Display page) Here's how to define a Scheme procedure. Operators like + and * are names of Scheme procedures. Thus you've just seen how to use a Scheme procedure: you form a parenthesized expression in which the first thing after the left parenthesis is the name of the procedure and the rest of the things are the operands—the inputs or arguments—that the procedure will use to produce its answer. (Using a procedure in this way is called calling or invoking it.) Scheme has around 100 built-in procedures. They form a general- purpose set of building blocks. Programmers use these built-in procedures to build their own procedures, in effect extending the language. These new procedures can then be used to define even more complex and sophisticated procedures. Using building blocks in this way is a good way to solve difficult problems. Here's an example of how to define a Scheme procedure.

(define (square x) (* x x) ) The definition has four parts:

the word define, which tells the Scheme interpreter you are defining something; the name of the procedure you're defining, square in this case; the names of placeholders for information that the procedure will use to produce its result; the body of the procedure, the Scheme expression that will be evaluated to produce the result.

There should be one placeholder name for each argument that's expected when the procedure is invoked. The square procedure needs only one piece of information, the number to be squared. Thus it has only one placeholder, which we arbitrarily name x. The procedure name and the placeholder names all go within a second set of parentheses. To square a number, we multiply it by itself. Thus the body of the square procedure represents the result of multiplying whatever the number to be squared is, by itself. 2.3.2 (Display page) Experiment with the square procedure. First type square to the Scheme interpreter to verify that the name "square" is currently undefined. Type the definition of square into the Scheme interpreter, and type square to see what has changed. Then, in a single expression, use it to find the square of the square of 49 (namely, 5764801). Then provide erroneous calls to square that produce the following error messages.

too many arguments to ... too few arguments to ... not a number: ... 2.3.3 (Display page) Put the interesting errors in your notebook. Put a note in your notebook about the errors that are most likely for you to make and the error messages that result. 2.3.4 (Display page) What are placeholders for? Placeholders, called parameters in the textbook, provide a mechanism for making procedures more general. For example, one might have a lot of special-purpose squaring procedures:

(define (square-of-4) (* 4 4)) (define (square-of-7) (* 7 7)) (define (square-of-92) (* 92 92)) But these procedures are all doing essentially the same thing. We capture that similarity by representing the differences with a variable, the placeholder name. 2.3.5 (Display page) How are procedure calls evaluated? Earlier, we discussed rules for evaluating Scheme expressions involving + and *. Here is how evaluation of a call to a user-defined procedure works.

1. The first word after the left parenthesis is looked up among the name of procedures that are either built-in or that have been defined by the user. 2. The arguments are counted to make sure they match the number of placeholder names. 3. The arguments are evaluated. (This has the effect of the "inside-out" evaluation we did with expressions involving + and *.) 4. The argument values are substituted for the corresponding placeholder names throughout the body of the procedure. 5. The body expression is evaluated, and the result is the value of the procedure call.

Here's how to evaluate the expression

(square (+ 2 1))

1. The Scheme interpreter notes that square has been defined to take 1 argument, and 1 argument has been provided in the call. 2. The argument expression (+ 2 1) is evaluated, producing a value of 3. 3. Since the placeholder for square is named x, 3 is substituted for every occurrence of x in the body of square, (* x x), giving (* 3 3). http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 2 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

4. (* 3 3) is evaluated, giving 9.

2.3.6 (Evidence) Diagrams can represent procedures you define. We talked about a visual representation of procedures earlier. It works for procedures that you write as well as the builtin ones. What would the machine be for this Scheme code?

(define (dist x1 y1 x2 y2) (sqrt (+ (square (- x1 x2)) (square (- y1 y2))))) Before clicking here , sketch just the (sqrt (+ (square (- x1 x2)) (square (- y1 y2)))) part in your notebook. 2.3.7 (Display page) Here's how tasks for writing procedures will look. Many of the tasks we'll be asking you to do in this course will involve writing procedures. Here's an example problem statement.

Write a procedure named sales-tax that, given the amount of a taxable sale, returns the sales tax applied to that sale. (The Alameda County sales tax rate is 9.75%.) For example, the call

(sales-tax 150.00) should return 14.625.

Here is one way to solve this problem.

1. From "write a procedure named sales-tax ...", we get the following framework.

(define (sales-tax ...) ... )

2. From "given the amount of a taxable sale" and the example, we conclude that sales-tax will take one argument and that we will need one placeholder. We choose to name it "amount".

(define (sales-tax amount) ... ) 3. We know that to get the amount of sales tax, we multiply the tax rate by the amount. That gives us the body of the procedure:

(define (sales-tax amount) (* .0975 amount) )

2.3.8 (Display page) Now you do it. Write a procedure named discount-price. This procedure is given two arguments:

1. the price of an item; 2. a discount rate (a value between 0 and 1.0) to be applied to that item. For example, a discount rate of .25 means that the selling price of the item will be three-fourths of its regular price.

Here are some sample calls to discount-price and their intended results. expression value (discount-price 1000.0 .25) 750.0 (discount-price 10.0 .40) 6.0 Type your procedure into the Scheme interpreter, then test it by evaluating the two expressions above. 2.3.9 (Display page) Use the Editor. When preparing a presentation, one organizes it ahead of time rather than just giving it "off the cuff". Similarly, when building a program, we generally don't type the procedures directly into the Scheme interpreter. We use a "scratch pad" called an editor, save the program we type there into a file, and then load it into the Scheme interpreter all at once. An editor is much like Microsoft Word, for example, except that it has features that make writing Scheme code easy. We will use the "emacs" editor in this class. Emacs is very full featured, but you only need to use a few. It has menus at the top like many other editors. We will go into more detail about the emacs editor later today, but you use it a little bit now. (You might skip ahead to the Emacs and Unix Tutorial below). You start the editor by typing emacs& at the unix prompt:

h30 [1] ~/ > emacs& [1] 22588 h30 [3] ~/ > Note that you need to type this at the unix prompt, not the STk prompt! You can get another terminal, with a unix prompt, at any time via the right mouse button. When starting emacs in this way, you will first need to open a file or start a new one. Do this via the "File" menu, "Open File", and typing the file name (which will appear in the area at the bottom of the emacs window). Start the new file "discount-price.scm" by going to File, Open File, and typing in "discount-price.scm" at the bottom of your Emacs window. Type your definition of the discount-price procedure into the editor and save the file. You can run STk from inside Emacs by holding the diamond key (by the space bar) and pressing the 's' key. This splits your Emacs window into two parts. The top part is where you edit your file, and the bottom part is where you run STk. You can copy and paste code from the top part to the STk below. But Ctrl+C and Ctrl+V don't work in emacs so you will need to use the edit menu or learn the emacs short-cuts. You can also highlight the code in the top and use the Scheme menu to "Send region" Once you do this, evaluate a call to discount-price to make sure the procedure was loaded successfully. 2.3.10 (Display page) What is Scheme waiting for? At this point we assume that you have emacs opened with two windows. On the top, you should have a text editor and on the bottom, your STk prompt. On the bottom of your emacs try typing out the procedure for square. (define (square x) (* x x)) Try having the definition span 2 lines. What about 3 lines or 10? What happens when you hit return before typing the last parenthesis? If you want to stop before typing the last parenthesis you can type Ctrl+D. Try it! Try highlighting the square definition and clicking on the menu option Scheme->Send Region. What happens if you don't highlight the ending parenthesis? How can you recognize this problem if it happens? What should you do when it happens. Talk to the person next to you about it. 2.4 Think about possible errors.(3 steps) 2.4.1 (Brainstorm) What change causes an "unbound variable: x" message? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 3 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Recall the square procedure:

(define (square x) (* x x) ) One of your classmates changes a single symbol in the procedure so that, when the expression (square 4) is evaluated, the error message

Error: unbound variable: x is produced. What was the symbol that was changed, and how did you figure out what it was? 2.4.2 (Brainstorm) What does this procedure do? A student enters the following definition into the Scheme interpreter:

(define (f x) (* x 3) (+ x 10) )

Experiment with this procedure using the interpreter, then explain what it returns for a given x. 2.4.3 (Brainstorm) What might the procedure's author expect it to do? The author of the procedure just described (it also appears below) may have been confused about how Scheme evaluation works. What might this person have expected it to do, and why?

(define (f x) (* x 3) (+ x 10) ) 2.5 Solve some problems that use more than one procedure.(3 steps) 2.5.1 (Display page) Find the total selling price of an item. Copy the sales-tax and discount-price procedures into the Scheme editor. Then use them to help define a procedure named selling-price, which when given the undiscounted price of an item and a discount rate (a number between 0 and 1.0), returns the total selling price of the discounted item, that is, discounted price plus 8.25% sales tax. Save the three procedures into a file named "sales.scm", load them into the Scheme interpreter, and then test them. 2.5.2 (Brainstorm) Figure out what a procedure does. With the person sitting next to you, experiment with the mystery procedure defined below and come up with a better name for it.

(define (mystery x) (square (+ 1 (truncate (sqrt (- x 1))))) )

The sqrt procedure returns the square root of its argument (the value that, when squared, produces the argument). The truncate procedure returns the result of subtracting any fractional part from its argument; thus the value of

(truncate 4.79) is 4.0. 2.5.3 (Display page) Find the day of the year for a given date in the French Revolutionary calendar. The French Revolutionary calendar, in use in France between 1793 and 1806, divided the year into 12 months of 30 days each, followed by 5 monthless days. Write a procedure named day-of-year that, given a month number and a date in that month in the French Revolutionary calendar, returns the day of the year. The month number argument will be a number between 1 and 12, inclusive; the date in that month will be a number between 1 and 30, inclusive. Here are some examples of how day-of-year should work.

expression value (day-of-year 1 1) 1 (day-of-year 1 30) 30 (day-of-year 2 1) 31 (day-of-year 12 30) 360 2.6 Review new vocabulary.(1 step) 2.6.1 (Display page) Make sure you understand terms we've used today. The following terms were discussed today:

argument body expression evaluation input placeholder procedure result

Review these terms with a person sitting next to you, and make sure you both understand them. Provide each other with examples. Put an entry in your Extra Brain for each of the definitions that you expect to have a hard time remembering. 2.7 Homework(3 steps) 2.7.1 (Display page) Reading in Simply Scheme The majority of time, you will have homework for each lab session. Why should the first session be any different? Generally, homework will come at the end of the day's activities, and may have several parts. This one, for instance, has three parts. You are, of course, encouraged to work on your homework within lab!

1. Read chapters 3 and 4 in Simply Scheme, which reviews the material from today. Also read chapter 5, which covers material for next session.

Note that reading assignments are shown at the bottom of the calendar, in the course portal, in red.

2. The page (step) after this one contains several exercises. Do them. 3. The third step contains a new tool called a "Discussion Forum". You can create discussion threads here; that is, you can start new topics, or reply to existing comments. Contribute a post and comment on two posts from other students.

2.7.2 (Display page) Exercises Exercises

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 4 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

1. Write a procedure named fifteen that takes no arguments, and returns 15. 2. Write a procedure named identity that, given any argument, returns the argument. 3. Do three of the five parts to exercise 4.4 in Simply Scheme (be sure you explain what was wrong with the original code), and test your procedures. The text of exercise 4.4 is available here.

How to submit

You will need both the editor and a unix (xterm) window. Use the editor to create a file named hwk1.scm, and put it in a directory (folder) named "hwk1". Here's how you do this:

1. To make the hwk1 folder, type mkdir hwk1 in the unix window and press return. 2. To get into the directory, type cd hwk1 in the unix window and press return. 3. To make the file, use emacs like normal.

Then put the definitions of the homework procedures into this file:

fifteen identity

(three of the following five): sphere-volume next square triangle-area sum-of-squares

After the definitions of fifteen and identity, include test call(s). After the other three definitions, include an explanation of why the original version was wrong and give the tests that you used to make sure your new procedures worked. Remember, you can copy from the stk text and paste into your editor. Save the file. Print the definitions of all these procedures (you can print from emacs via the "File" menu). Hand the printed definitions to your instructor at the start of the next lab. 2.7.3 (Discussion Forum) What's the best name for the mystery procedure? You chose a better name for the mystery procedure in lab, then you reviewed the choices that your classmates made. What's the best name you saw? In a post, defend your choice; then in responses, (politely) criticize two of your classmates' choices. 3 Emacs and Unix Tutorial 2009-8-27 ~ 2009-8-28 (4 activities) 3.1 Working with Unix(5 steps) 3.1.1 (Display page) The Basics If you want to use a computer, you need software that lets you talk to your machine. Most of you use Windows or MacOS for this. However, in CS 3, we use something called Unix. Some parts of Unix might seem familiar to you. You can open windows, run a web browser, and use the mouse in pretty much the same way you would with Windows or MacOS. However, you will also need to use the keyboard with Unix. You type commands into Unix in special windows called xterm windows. One should be on your screen right now. If the top part of the window is white, that means it is active. You can type into it. If the top part is blue, it is not active and you can't type into it. About the only way to make a window active is by clicking on the top part. If you close your xterm window or need another one, right-click on the background. A menu will pop up, and you can select "xterm."

We haven't mentioned this, but you can easily quit from the stk program by typing (exit) at the stk prompt. This will bring you back to a unix prompt.

Your reader contains a simple one-page cheat sheet on Unix that you may find useful. You will also find the page under the "Resources" menu in the course portal. 3.1.2 (Display page) Looking at directories Files in Unix are organized a lot like they are on other computers. You keep them inside folders. However, you can't really see you folders on Unix. You can type "ls" to get a list of everything in your current folder.

h30 [3] ~ > ls discount-price.scm sales.scm ucwise@ h30 [4] ~ > You start with one folder, and it is called "ucwise." (You made the two scheme files (and possibly more) in earlier steps) The "ucwise" folder is where you will keep all of your files. Type "cd ucwise" to go into this folder. (Folders are also called "directories," so "cd" means "change directory.")

h30 [4] ~ > cd ucwise h30 [5] ~/ucwise > So now you're in your ucwise folder. You will need to keep each homework assignment in its own folder. Type "mkdir hw1" to make a folder called "hw1."

h30 [12] ~/ucwise > mkdir hw1 h30 [13] ~/ucwise > ls hw1/ h30 [14] ~/ucwise > Now you can see your hw1 folder. Now let's move into that folder.

h30 [14] ~/ucwise > cd hw1 h30 [15] ~/ucwise/hw1 > ls h30 [16] ~/ucwise/hw1 > Okay, there are no files inside hw1. How do we get back out? Well, you can type "cd .." to go up one folder.

h30 [16] ~/ucwise/hw1 > cd .. h30 [17] ~/ucwise > Now you are back to your good old ucwise folder. 3.1.3 (Display page) Moving files around You can also do things like copy files and folders, move them around, rename them, and delete them. You'll probably want to wait until after you have some files, but here's how to do each of those things: to do this you type example http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 5 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

copy a file or cp [from here] cp hw1answers.scm hw1 copies the file folder [to here] "hw1answers.scm" to the hw1 folder.

move a file or mv [from here] mv hw1answers.scm hw1 moves the file folder [to here] "hw1answers.scm" to the hw1 folder.

rename a file mv [old name] mv hw2a hw2answers.scm renames the file or folder [new name] "hw2a" to "hw2answers.scm" rm hw2answers.scm erases the file delete a file rm [filename] "hw2answers.scm" Here's another little trick. The ".." that lets you move up one folder will let you do a lot more. Let's say you are in your hw1 directory and you want to see what's in your ucwise folder (the one above hw1).

h30 [22] ~/ucwise/hw1 > ls .. example hw1/ h30 [23] ~/ucwise/hw1 > This shows you everything in your ucwise folder. In this case, we also have a file called "example." What if you want to move this file into your hw1 folder? Well, ".." means "one folder up," and "." means "this folder."

h30 [23] ~/ucwise/hw1 > mv ../example . h30 [24] ~/ucwise/hw1 > ls example h30 [25] ~/ucwise/hw1 > ls .. hw1/ h30 [26] ~/ucwise/hw1 > What, exactly, does "mv ../example ." mean? You know what mv means. The .. means "go up one folder." "../example" means "the file called 'example' in the next folder up." The . means "the folder I'm in right now." Thus, "mv ../example ." means, "Take the file called 'example' in the next folder up and put it in this folder." Now let's go back to your ucwise folder. How do we get the example file out of the hw1 folder?

h30 [26] ~/ucwise/hw1 > cd .. h30 [27] ~/ucwise > mv hw1/example . h30 [28] ~/ucwise > ls example hw1/ h30 [29] ~/ucwise > In this case, "mv hw1/example ." means, "Take the file called 'example' in the hw1 folder and move it to this folder." 3.1.4 (Display page) Move those scheme files! With your new found skills, move the two Scheme files that you made earlier today into your "ucwise" directory. Right now, they are in your home directory (the one containing ucwise). 3.1.5 (Display page) Running other programs There are three major programs you'll want to run in this class. The first is called Mozilla. Mozilla is a web browser that is a lot like Netscape, but much, much better. You'll use Mozilla for every lab, since most of the lab materials are on the web. The second is called STk. STk is the Scheme interpreter we use. You type in Scheme code and it runs your program. You'll use it a lot, too. The third is called Emacs. Emacs is a text editor. It's kind of like Notepad or Simpletext or Word, but it's better for programming. For one thing, it color-codes your programs so you can see different parts easily. It also lets you write a Scheme program, edit it, save it, and then run it in STk. You can run one of these programs by typing the right name into xterm. Make sure you type the names in all lower-case letters. However, when you run a program in Unix, it locks your xterm window. If you type "mozilla," you will get a Mozilla window that will let you browse the web, but you can't use your xterm window anymore. There is an easy way around this. When you run Mozilla or Emacs, leave a space after the name and type "&" before you hit return.

h30 [16] ~/ucwise/> mozilla & h30 [17] ~/ucwise > You can still use your xterm window. Important: STk does not open its own window. If you run STk on its own, it will use your xterm window. This is just how STk works. This means you can't put an "&" after STk. If you do, bad things will happen. Fortunately, you'll almost always run STk from inside of Emacs. You can probably figure out how to use Mozilla, and we'll show you how to use STk throughout the whole semester. The program you really need to worry about is Emacs. We'll spend the rest of this tutorial talking about it. 3.2 Starting Emacs(2 steps) 3.2.1 (Display page) What is Emacs? Welcome to the world of Emacs!

You have already seen a little bit of emacs, and used it to write some scheme files. Emacs is actually one of the most common programs used by computer scientists to write programs, books, and even e-mail. Emacs isn't the friendliest of text editors, but it is quite powerful. This tutorial will take you through the basics of emacs. 3.2.2 (Display page) Entering Emacs from the Unix prompt Let's get cracking!

Now that you have a gist of what emacs is about, we can go ahead and try to access it from our Unix prompt.

Before you can access emacs you will need to have an xterm window open on your screen. An xterm window is a window that has a prompt that looks something like:

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 6 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Do note that this is an image of an xterm window via an SSH client, as many of the images are in the remainder of this tutorial, which will not look exactly like the xterm windows you will see on the computers you use in the lab. Nonetheless, the contents should look about the same. If you do not have an xterm window open you may open one up by either of the two methods

1. right-clicking on your desktop and on the menu that appears and select 'xterm' 2. through an xterm that is already open, type xterm& at the prompt.

Now at your command prompt, to open up Emacs type the command emacs&:

3.3 Emacs basics(5 steps) 3.3.1 (Display page) Take a look around Take a look closer...

When you have successfully entered Emacs you will see a new window on your screen that looks like this:

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 7 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Please note the menu bar that is circled in red--this will be helpful to you later.

The large space below this is called the buffer, where you will be doing all your text editing.

As you can see, some information already in the buffer tells you that Emacs does have its own tutorial provided for users. However, this tutorial should be sufficient to teach you what is necessary to navigate comfortably through the editor. If you would like a more in-depth understanding of Emacs' commands or more advanced commands, you may access their tutorial at your convenience. Now take note of the line at the bottom of your Emacs window--this is called the minibuffer which we'll talk about later in the tutorial. The line immediately above this will also be important to you later:

3.3.2 (Display page) Emacs has a lot of menu options http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 8 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Easy Sch-measy!

Do you remember the menu bar at the top of your Emacs window? You can use your mouse and click on each of the different options, just like how you would in the Windows operating system; for example, if you look for the Tools option

and click on it, a drop-down menu will appear and display all the different commands available for your selection. By simply selecting the command with your mouse you can execute commands this way through Emacs. Emacs has a lot of menus, and they all have a lot of options. Fortunately, you don't need to know them all. Really, you'll only need to use the File, Edit, and Scheme menus. File menu You can open, close, and save files (Emacs calls them "buffers"), as well as exit Emacs. Opening files doesn't work quite like it does in Word. We'll cover this in a minute. Edit menu You can copy, paste, cut, undo, and search. Scheme menu You won't see this menu until you have a Scheme file open. We'll do that in a few steps. Basically, this menu lets you send Scheme code you have written with Emacs to be interpreted by STk. This is really handy. 3.3.3 (Display page) Let's try creating a file Create a new file

Now we have a lot of tools under our belt for use, let's try doing something constructive with them. As text editors are used primarily for saving, modifying and creating text, we can now create a file that we can access later. Within your Emacs window, go to the File menu and select "Open File." Now look at the bottom of the Emacs window. It should look like

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 9 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

This little are is called the minibuffer, and what it shows is the path, or the location, in which Emacs wants to start looking for the file. If you are in your ucwise directory, the minibuffer should say "Find file: ~/ucwise/" instead of what it says in the picture. That means Emacs is looking in the ucwise directory. If you save a file, it will go there. If your minibuffer just says "Find file: ~/" you are not in ucwise. Be sure to type "ucwise/" before you type a file name, assuming this file is for your lab. If you type in a file name that already exists, Emacs will open it. However, since there aren't any files in your ucwise folder, Emacs will create a new one and name it whatever you want. Let's create a file called favethings.txt in your ucwise directory. Your minibuffer should look like "Find file: ~/favethings.txt." We don't need to put it in the ucwise folder, since this is just an experiment. Upon hitting enter, look at the line immediately above the minibuffer line. By careful inspection, each one tells you the type of file you are editing, the name of the file you are editing, and where the file is located (or, its path.) In our case it will look like

You will notice that the type of file you are editing is a text file, but if you were to modify a Scheme file it will say Scheme instead. The minibuffer line, upon trying to find a file that does not already exist, will display a message specifying that you are creating a new file. Basically the minibuffer and the area right above it show you any editor commands that you may enter in, the result of executing a command (in this case, the result of trying to find and open a file), or any editor information. Once you have identified that all of this correctly is in your window, you may go to the empty space of the window and start typing. For this exercise, answer the following questions:

1. What is your favorite color? 2. What is your favorite ice cream flavor? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 10 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

3. Do you like going to bed late at night/early morning or earlier at night?

3.3.4 (Display page) Gone in the blink of an eye... Saving is everything

One thing that all computer science students will learn inevitably at one time or another in their Berkeley career is to always save their files. Many students will tell you about their sad story of having a thousand line program on their screen one minute, and nothing but an error message the next. Unfortuantely, this is not something we can control. Professors usually do not empathsise with this mistake--so make a good habit of saving your work before you become another statistic. Go ahead and save your file in your directory (open the File menu and pick "Save (current buffer)"). And to make sure that you have saved and edited correctly, exit Emacs, open it up again and try retrieving your file. 3.3.5 (Display page) Learning more There are many ways for you to learn more about emacs. Perhaps the easiest is to run the "Emacs tutorial" from the "Help" menu (although, this isn't a particularly pretty tutorial). There are many documents on the web that you might find helpful. Additionally, a reference sheet is included in your reader. 3.4 Programming with Emacs(3 steps) 3.4.1 (Display page) Create some Scheme files Make a Scheme file

Congratulations. You have made it this far!

Now one more important point that should be mentioned: whenever you save your files in Emacs, be sure to specify the type of file that you are editing. Otherwise, Emacs will assume that it is a text file. To tell Emacs what kind of file you are creating/opening we add on what we call a file extension to the end of the file name. If you remember, the favethings.txt is specified to be a text file with the .txt file extension. For CS3, we identify Scheme files with the .scm extension.

With this in mind, let's try creating a Scheme file. Call it "firstfile.scm" and make sure you save it in your ucwise directory. Even though you probably don't know any Scheme yet, try typing some into Emacs. We'll help you. Type this:

(define (firstprogram x) (+ x 5)) You sould notice three things. First, there are a couple of different colors on the screen. As you get used to Scheme, these will help you see different parts of your code. Second, whenever your cursor is on or next to a parenthesis, the other parenthesis that goes with that one is highlighted. Scheme is full of parentheses, so this will be really helpful. Finally, Emacs automatically indented the second line. This also makes your code easier to follow. 3.4.2 (Display page) Say hello to STk My friend, STk

This is a class on Scheme, not Emacs, so it's about time we show you how to actually run Scheme code. You need a Scheme interpreter, like STk. Fortunately, you can run STk from inside Emacs. There are two ways to do this. First, you could hold the Meta key (the diamond) on the keyboard and press the "s" key (we'll write this "M-s" for Meta-s). Second, you could go to the Scheme menu (it will only be there if you have a Scheme file open right now) and select "run Scheme in a split window." Either way, your Emacs window should now look something like

Now you have a regular STk interaction window! It is exactly the same as any other interaction window that you have used so far (i.e. the Listener). You can type expressions or functions into it, as well as highlight, http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 11 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

copy and paste functions from the Emacs editor.

Let's say you have typed the following into the top buffer of Emacs:

(define (double x) (* x 2))

(define (square x) (* x x))

With STk running in the bottom of the window, put your cursor at the start of the definition for double and press M-p (hold the diamond key and press "p"). Emacs gives the definition of double to STk and moves your cursor to the next definition. Now Emacs really talks to STk. One final neat feature of STk is that it can load in whole Scheme files so you don't have to define everything every time. Try saving this file as "examples.scm." Go to STk and type (load "examples.scm"). Now you can use double and square as though you had typed them into STk. 3.4.3 (Display page) Conclusion La fin

Well, if you have reached this step then you have successfully completed the UC-WISE version of the Emacs tutorial. With much practice and usage, you will grow to love (or possibly hate) Emacs, but it will definitely be useful to you in your Berkeley career if you so choose to continue with the lower division computer science courses. In fact, all course work in the cs61 series can be very conveniently done using Emacs, although you are not bound to only this editor.

If you would like to learn more of the [much] cooler commands that Emacs has to offer, please go through their tutorial that you can access through the menu bar under Help.

Thank you for participating in the CS3 Emacs tutorial and have a good day!

Entire day brainstorm answers"" 5 Working with words and sentences 2009-9-01 ~ 2009-9-02 (9 activities) 5.2 Experiment with word arguments and quoting.(7 steps) 5.2.1 (Display page) Review some builtin procedures that take words as arguments. Review some builtin procedures that take words as inputs.

Up to now, we've worked only with procedures that take numbers as inputs (arguments) and return numbers as values. As you learned from yesterday's reading assignment, the Scheme interpreter also has builtin procedures that work with words and sentences. We'll initially start experimenting with words and then move on to sentences. Two builtin procedures of interest are

first, which, given a word as input, returns the first character of that word; butfirst, which, given a word as input, returns the result of removing the first character of the input. last, which, given a word as input, returns the last character of that word; butlast, which, given a word as input, returns the result of removing the last character of the input.

It's an error to give a word with no characters to first or last or butfirst or butlast. 5.2.2 (Brainstorm) Why do we need to quote a word argument to first? Experiment in the Scheme interpreter with the first procedure. You will find that

(first mike) produces an error, while

(first (quote mike))

returns an "m". Explain why evaluating (first mike) produces an error message. 5.2.3 (Display page) Why didn't we need to use quote with numbers? Why didn't we need to use quote with numbers?

Numbers in Scheme are self-evaluating; that is, they evaluate to themselves. This is why you can say

(+ 1 2 3 4) instead of

(+ (quote 1) (quote 2) (quote 3) (quote 4)) It's OK to quote numbers if you want, but not necessary. 5.2.4 (Brainstorm) Examine quoting in a slightly different context. Now type the following procedures into the Scheme interpreter.

(define (initial1 name) (first name) )

(define (initial2 name) (first (quote name)) ) Try to use each procedure to find Mike's first initial, by supplying the word

mike to each as an argument. That is, what happens when you call

(initial1 'mike) and

(initial2 'mike) Explain what each procedure is doing, and why. 5.2.5 (Display page) Now try it with the word procedure. Now try it with the word procedure.

The word builtin procedure takes any number of words as arguments (it's like the + and * http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 12 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

procedures, which take any number of numbers as arguments), and returns the result of gluing all the words together into a single word. Here's an example:

>(word (quote i) (quote am) (quote bic)) iambic

Write and test a procedure named plural that returns the result of gluing an "s" onto the end of its argument. Put your procedure into a file named plural.scm. Here are examples of how plural would be used.

>(plural (quote house)) houses >(plural (quote guess)) guesss 5.2.6 (Display page) Here's an abbreviation for quote. Here's an abbreviation for quote.

The quoting operation is used so often that Scheme provides an abbreviation for quote: the expression

'x is translated by the Scheme interpreter into the expression

(quote x) for any x. 5.2.7 (WebScheme) Try taking words apart Predict the result of some expressions

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. If you think one of the calls will give you an error, put "error" in the blank. Scheme Expression Value Correct?

(first 'oneword)

(butfirst 'oneword)

(first 10)

(butfirst 10)

(first 'a)

(butfirst 'a)

(first "")

(butfirst "")

5.3 Experiment with sentences.(6 steps) 5.3.1 (Display page) Here is how sentences work. Here is how sentences work.

A sentence is a list of words surrounded by parentheses. Here is a two-word sentence:

(mike clancy)

The sentence procedure takes any number of arguments; each must be a word or a sentence. It returns a sentence that contains all the words from the arguments, in order. An example:

> (sentence (quote mary) (quote (had a little)) (quote lamb)) (mary had a little lamb) Another example, using the quote shortcut:

> (sentence 'the 'quick '(brown fox jumped) 'over '(the lazy dog)) (the quick brown fox jumped over the lazy dog) The empty sentence is the sentence without any words, namely

( ) 5.3.2 (WebScheme) Predict the values of some expressions. Predict the result of some expressions

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Value Correct?

(sentence 'I '(me mine))

(sentence '( ) '(is empty))

(word 'ab 'cd)

(sentence 'ab 'cd)

(sentence 'a (word 'k 'c))

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 13 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

5.3.3 (WebScheme) Experiment with words and sentences. Experiment with words and sentences

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Right Your Scheme Expression Correct? Answer Answer

( 'a 'b) ab ????

( 'a 'b) (a b) ????

( 'a ( 'b 'c)) (a bc) ????

(ab c (sentence (word 'a 'b) (sentence )) ???? d) (a b ( 'a ( 'b 'c)) ???? c) (a b c (sentence (sentence 'c 'd)) ???? d)

5.3.4 (Display page) First and butfirst work both with words and with sentences. first and butfirst work with both words and sentences.

The first procedure, applied to a sentence, returns the first word of that sentence. Similarly, the butfirst procedure, given a sentence as argument, returns the result of removing the first word from the sentence. Given an empty sentence as argument, both first and butfirst produce an error. Because first and butfirst can take both words and sentences as arguments, sometimes it's difficult to keep track in a complicated expression about which is which. 5.3.5 (WebScheme) Practice working with words and sentences in the same expression. Predict the result of some expressions

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Value Correct?

(butfirst 'a)

(butfirst '(a))

(butfirst (first 'abc))

(butfirst (first '(abc)))

(butfirst (first '(ab cd ef)))

5.3.6 (WebScheme) Practice with more challenging expressions. Practice with more challenging expressions

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Right Your Scheme Expression Correct? Answer Answer

(first (butfirst )) abc ????

(butfirst (first )) abc ????

( ( '(abc def ghi))) a ????

( ( '(abc def ghi))) def ????

( ( '(abc def ghi))) (ghi) ????

5.4 Review words, sentences, and quotes.(4 steps) 5.4.1 (Display page) An interesting analogy A sentence is a collection of words. A word is a collection of letters. Words and sentences are similar to Pez candy dispensers. Here's a basic summary of the argument:

The sentence or word itself is the dispenser Individual words in the sentence or letters in the word are like the candies. Individual candies are in a specific order within the dispenser, just like individual words or letters are in a specific order within the sentence or word. With a flip of your finger, you can separate the first candy (first) from the dispenser and all of the rest of the candies (butfirst). You can use those two procedures to separate the first word or letter from the rest of the sentence or word. As long as it is your Pez dispenser, it's OK to take the last candy out. It's also OK to take the first or butfirst of a one-word sentence or a one-letter word. People collect empty Pez dispensers. (I promise I'm not making this up. If you don't believe me, check out the Burlingame Pez Museum.) It's equally OK in Scheme to have an empty sentence (it looks like ( )) or an empty word (it looks like ""). A Pez dispenser is only empty when it doesn't have any candy at all in it. You can't just say http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 14 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

it's empty if the last thing in there is a candy you don't like. Likewise, you can't say a sentence is empty just because you don't like what it contains. If "" is still a word, ("") is not an empty sentence.

Don't go too crazy with the analogy, though. You can pop the top on a Pez dispenser even after it's empty, although you won't get any candy. If you try to take apart an empty word or sentence, Scheme throws a fit. 5.4.2 (Brainstorm) Review evaluation when quotes are involved. Explain the difference in meaning between

(first 'mezzanine) and

(first '(mezzanine)) Don't just say, "The first one returns this and the second returns that." Explain why they are different. Do the same for

(first (square 7)) and

(first '(square 7)) 5.4.3 (Brainstorm) Review special cases for butfirst. Explain the difference between

(butfirst 'x) and

(butfirst '(x)) Again, tell why they act the way they do. Don't just say they give different answers. 5.4.4 (Display page) Things get trickier here. Things get trickier here.

Supply parentheses and quotes in the line below so that when you evaluate the result, you get (def ghi).

butfirst sentence abc word def ghi To check your answer, either type the expression into the Scheme interpreter or ask the person sitting next to you to verify it. (Or do both.) 5.5 Experiment with "appearances".(1 step) 5.5.1 (Brainstorm) Find out about "appearances". Appearances is a builtin procedure that returns some information about how one of its arguments relates to another. Your task is to find out how many and what types of arguments it takes, and what information it returns about those arguments. Knowing how to figure out what a procedure does just by playing with it is a really handy skill, but it can be frustrating. Consider the error messages carefully; your TA can help you make sense of them. If you aren't having any luck, talk to your neighbors and TA! 5.6 Think about evaluating expressions with quotes.(2 steps) 5.6.1 (Display page) Here is how expressions with quotes are evaluated. Here is how expressions, including those with quotes, are evaluated.

Earlier, we discussed rules for evaluating Scheme expressions involving user-defined procedures. Here is how evaluation of possibly quoted expressions works.

1. Does the expression contain parentheses? (I.e. is it a "simple" expression without parentheses or a "complicated" expression with parentheses?) Note that a quoted expression such as '(x y) is "complicated", since it really is (quote (x y)). If it's a number, it's self- evaluating; its value is the number itself. If it's a word, it should have been associated with a value, so that value is returned.

2. Otherwise, the expression starts with a left parenthesis. Is "quote" the first word after the left parenthesis? If so, return the quoted word or sentence. Quote is called a special form since it is evaluated in this special-case way.

3. Otherwise, the first word after the left parenthesis should name a procedure; it is looked up among the name of procedures that are either built-in or that have been defined by the user.

4. The arguments are counted to make sure they match the number of placeholder names.

5. The arguments are evaluated; that is, scheme will work through these 7 steps separately for each of the arguments. (This has the effect of the "inside-out" evaluation we did with expressions involving + and *.)

6. The argument values are substituted for the corresponding placeholder names throughout the body of the procedure.

7. The body expression is evaluated, and the result is the value of the procedure call.

5.6.2 (Brainstorm) Here's something to watch out for. A problem arises when a procedure's placeholder name is the same as the name of a builtin procedure that the procedure is trying to use. Here's an example:

(define (plural word) (word word 's) ) Explain what will happen as a result of evaluating

(plural 'house) Also, explain why it happens. 5.7 Use a sentence to "package" information.(3 steps) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 15 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

5.7.1 (Display page) Why package information? Why package information?

A Scheme procedure can only return a single value. When a procedure needs to return two related pieces of information, we typically combine the two into a sentence and then return that. Similarly, instead of designing a procedure to take several related arguments, we often code it to take a single sentence as an argument and then access the parts of the sentence within the procedure. Here's an example. Suppose we want to determine how many inches a given measurement—in feet and inches—represents. We might code this as

(define (inch-count feet inches) (+ (* 12 feet) inches) ) But if we wanted to define the inverse procedure, which would take a measurement in inches and return the corresponding number of feet and inches, we would have to return a two-word sentence that contains the feet and inches (or else write two separate procedures, one for feet and one for inches). 5.7.2 (Display page) Write procedures to work with measurements. Write procedures to work with measurements.

Thus we will represent a height measurement as a two-word sentence, with the first word being a nonnegative integer and the second being a number between 0 and 11, inclusive. Write and test a procedure inch-count that, given a height measurement as argument, returns the number of inches represented by that height. For example,

(inch-count '(2 3)) should return 27 (the number of inches represented by 2 feet, 3 inches). Then write and test a procedure height that, given a measurement in inches, returns the corresponding height measurement in feet and inches. The height and inch-count procedures will be inverses; the value of

(height (inch-count ___ ))

will, for any legal argument to inch-count, be equal to that argument, and the value of

(inch-count (height ____ )) will similarly be equal to the argument. Put both these procedures into a file named measurements.scm. You might find the procedures quotient and remainder to be useful here:

(quotient 10 4) ==> 2 (quotient 10 6) ==> 1 (remainder 10 4) ==> 2 (remainder 10 6) ==> 4 (remainder 10 5) ==> 0 A short document titled "Integer Division and its uses" is available online that should be helpful with problems requiring quotient, remainder, and the like. 5.7.3 (Display page) (optional) Translate a day in the French Revolutionary year... Write a procedure to translate a date in the French Revolutionary year to a sentence representing that date.

The following is a good, albeit involved, problem. We've made it optional for you: certainly try it, and don't give up it you have time to work on it. If you do need to leave it before finishing it today, consider coming back in a few weeks to finish it! Note that you can work on the two parts of this problem (getting the month, and getting the day of the month) independently - perhaps by working on procedures named FR-month and FR-day-of-month. Once you have both working, it's easy to put them together to make FR-date work correctly. You'll probably need to test your procedures-in- progress quite a bit. That is, code a little bit, test, code some more, test, and so forth. Remember that in the STk in emacs, you can "bring back" the last thing you typed by pressing the control key and the up-arrow key together. This will make it easy to repeat tests.

Write a procedure named FR-date that, given a day in the French Revolutionary calendar year--a positive integer less than 361--returns a sentence containing the month number and the date in that month. The month number will be an integer between 1 and 12, inclusive; the date in the month will be an integer between 1 and 30. Put your procedure into a file named FR-date.scm, and test it on the examples below.

expression value (FR-date 1) (1 1) (FR-date 2) (1 2) (FR-date 30) (1 30) (FR-date 31) (2 1) (FR-date 360) (12 30) You will find the document "Integer Division and its Uses", available in the CS3 reader as well as here, to be very useful. 5.8 Consider some typical student misconceptions.(5 steps) 5.8.1 (Evidence) Here are five ways students get confused. Here are five ways students get confused.

Students sometimes invent incorrect rules for using parentheses and quotes. Here are some examples of mistakes that many students have made over the years. These are taken from real life, or at least real students in CS 3. Odds are that several people in this very class will make some of these mistakes this semester. Each example includes the description of the rule, an example—an incorrect call to a procedure—of the rule, the correct call, and a framework for the definition of the procedure to be called.

Bad Rule 1

All arguments provided for a procedure are enclosed in parentheses and quotes. incorrect call resulting from following the rule correct call procedure definition

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 16 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(example1 (example1 (define (example1 wd1 wd2) 'a '(a thing)) ... ) 'thing)

Bad Rule 2

Sentences in general don't need to be quoted. incorrect call resulting from following the rule correct call procedure definition

(example2 (example2 (define (example2 sent1 sent2) (a b c) '(a b d) ... ) (d 2 f)) '(d 2 f))

Bad Rule 3

Sentences of numbers don't need to be quoted. incorrect call resulting from following the correct call procedure definition rule

(example3 (example3 (define (example3 numericSent) (5 18 299)) '(5 18 299)) ... )

Bad Rule 4

Words don't need to be quoted. incorrect call resulting from following the rule correct call procedure definition

(example4 (example4 try 'try (define (example4 wd1 wd2 wd3) this 'this ... ) out) 'out) Remember, if you don't quote a word, scheme will try to evaluate it, rather than use it literally.

Bad Rule 5

Quotes may go either inside or outside a sentence. incorrect call resulting from following correct call procedure definition the rule

(example5 (example5 (define (example5 sent) ('this 'is 'a 'sentence)) '(this is a sentence)) ... ) 5.8.2 (Brainstorm) Determine a student's misconceptions. A CS 3 student is given the following procedure, which returns the result of replacing the first word in its second argument by its first argument.

(define (first-replaced item sent) (sentence item (butfirst sent)) ) The student, hoping to produce the value

(red dog) calls first-replaced as follows:

(first-replaced red ()) Which incorrect rules for evaluation is the student using, and what is the proper call to first- replaced? Briefly explain your conclusion about the student. Hint: this is a good time to add another error or two to your list. 5.8.3 (Brainstorm) Determine another student's misconceptions. A CS 3 student is given the following procedure, which returns the result of gluing together each word in the first argument with the corresponding word in the second argument. (The student has previously defined the second and third procedures.)

(define (paired-sent sent1 sent2) (sentence (word (first sent1) (first sent2)) (word (second sent1) (second sent2)) (word (third sent1) (third sent2)) ) ) The student, hoping to produce the value

(a3 b7 c9)

calls paired-sent as follows:

(paired-sent ('a 'b 'c) (3 7 9))

Which incorrect rules for evaluation is the student using, and what is the proper call to paired- sent? Briefly explain your conclusion about the student and supply the correct call to paired-sent. Remember, the student has already written second and third. 5.8.4 (Brainstorm) Determine a third student's misconceptions. A CS 3 student is given the following procedure, which returns the result of attaching the square of the first argument to the second argument as its first word.

(define (square-attached num sent) (sentence (* num num) sent) ) The student, hoping to produce the value

(16 2 c f 3)

calls square-attached as follows:

(square-attached '(4) '(2 c f 3)) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 17 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Which incorrect rules for evaluation is the student using, and what is the proper call to square- attached? Briefly explain your conclusion about the student. 5.8.5 (Display page) Reminder: sometimes, in lab, you should look back at earlier materials. There are certain steps in your lab (Brainstorms and Discussion Forums) in which you can see other students comments and thoughts. You should occasionally revisit these steps, in order to get the most out of them. For instance, the last three steps were Brainstorm exercises. If you were the first student in your section to answer them, you didn't get to see any other responses! We recommend that every student go back, at least once, to look at new responses and consider the problem again. 5.9 Homework(3 steps) 5.9.1 (Display page) Homework activities Homework exercises to submit by the start of your next lab.

Make sure you read Chapter 6 of Simply Scheme. This isn't really an exercise, but be sure to do it anyway. Do exercises 5.13 and 5.19 in Simply Scheme (available here if you haven't yet gotten the book). Put solutions to these exercises, along with tests of your solution to 5.19, into a file named hwk2.scm in a directory (folder) called hwk2. This will be part of how you submit homework for this class. This is what you need to do:

1. From an xterm window, type mkdir hwk2 and press return. 2. To go into that directory, type cd hwk2 and press return. 3. Now use emacs to make the hwk2.scm file.

Print this file out and hand it in to your TA in the next lab session. In the following weeks, you will use an electronic submission program when you need to turn in homework. We will detail this procedure when it is ready. For this week, however, you will hand in printouts.

Also, be sure to finish all of today's activities by the start of the next lab.

Additional activities

Contribute at least one post and at least one reply to each of the following discussions. Go back to yesterday's homework discussion and make sure you leave thoughtful comments. 5.9.2 (Discussion Forum) Why are quotes and parentheses so hard to understand? Most people have at least a little trouble with quotes and parens. Do you find any of this confusing? How do you deal with it? If you don't have any problems with quotes or parens, give us a tip on how you make sense of it all. Be sure to make at least one thoughtful comment on somebody else's post. For grading purposes, "Right on!" and "I agree." don't count as thoughtful. 5.9.3 (Discussion Forum) English vs. Scheme Both English and Scheme have things called words and sentences. These are similar, but not identical. List at least two ways in which English words or sentences are like Scheme words or sentences and at least two ways in which they are not like Scheme words or sentences. Also, make at least one intelligent comment on a classmate's list. Just so you know, things like "Yeah!" do not count as intelligent responses, no matter how much thought you put into them. 6 Working with conditional expressions 2009-9-03 ~ 2009-9-04 (6 activities) 6.1 Practice with predicates and the "if" expression.(7 steps) 6.1.1 (Display page) Conditionals Introduction to Conditionals

So far, you have written programs that can, with enough code, transform numbers and words in very complex ways. But, the programs that you can create right now will lack a most basic feature of intelligence: the ability to do completely different things depending on what they "see" (i.e., what is passed as input). Today you will focus on conditionals, or statements that let your program branch in two or more different ways depending on some input. In the course of this, you'll also learn about how scheme can test inputs, in order to determine which branch to follow. 6.1.2 (Display page) Here is how "if" works, and "predicate" procedures that it works with. Here is how "if" works, and "predicate" procedures that it works with.

The if expression has the form

(if test-expression true-result false-result) It allows the programmer to write an expression whose value depends on the outcome of a test expression. An example, representing today's choice for dinner, is

(if (is-monday? today) 'macaroni-and-cheese 'chinese-food)

if takes three arguments. The first is an expression whose value is either true or false (these are defined below). The second and third are also expressions; one of these will be evaluated, and that value will be the result of the if expression, depending on whether the first argument's value was true or false. False is represented by the symbol #f. True is any value that's not #f. The symbol #t is often used for this purpose. Procedures used because they return true or false are called predicates. Scheme has a number of builtin predicate procedures, almost all of which have names that end in a question mark:

word?, given a single argument, returns #t if the argument is a word and returns #f otherwise. sentence?, given a single argument, returns #t if the argument is a sentence and returns #f otherwise. number?, given a single argument, returns #t if the argument is a number and returns #f otherwise. empty?, given a single argument, returns #t if the argument is the empty word or the empty sentence; it returns #f otherwise. member?, given two arguments, returns #t if the first argument is a "member" of the second--a character within a word or a word within a sentence. It returns #f otherwise. equal?, given two arguments, returns #t if they have the same value and #f otherwise. before?, given two words as arguments, returns #t if the first word comes alphabetically before the second; it returns #f otherwise.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 18 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

=, >, <, <=, and >=, given two numbers as arguments, return the result of the corresponding numeric comparisons.

Here is an example:

(if (> 5 4) (+ 3 7) (- 3 7))

Since 5 is bigger than 4, Scheme does (+ 3 7). It never even looks at (- 3 7). 6.1.3 (Display page) Experiment with builtin predicate procedures. Experiment with the built-in predicate procedures in the Scheme interpreter. In particular, answer the questions:

What happens when you try to compare letters with =? Does before? treat upper-case and lower-case letters identically? Are the decimal value 12.00 and the integer 12 equal? (Make this test using both equal? and =.)

Put the results in your Extra Brain. 6.1.4 (Display page) Experiment with "if". Experiment with if.

Complete the bodies of the following procedures, and test the results using the interpreter. Put the completed procedures and the results from your tests into a file named if-tests.scm. Your TA or lab assistant may ask you how you chose your test expressions.

; k is an integer. ; Return the smallest even number that's greater than k. (define (next-higher-even k) (if (odd? k) ___

___ ) )

; x is a sentence or word. ; If x isn't empty, return its first word or letter. ; If x is empty, return the word ILLEGAL. (define (non-crashing-first x) (if ______

___ ) )

; x and y are two numbers. ; Return the smaller of the two. (define (smaller x y) ___ ) 6.1.5 (Display page) "if" expressions can be nested. If expressions can be nested.

Any of the three expressions in an if may itself be an if expression. Here's an example:

(if (> water-temp 212) 'steam (if (< water-temp 32) 'ice 'liquid) )

Note that with the two nested if statements, there are three possible outcomes: steam, liquid, and ice.

Write and test a procedure named inches-in-range that takes three arguments. The first is a number in inches. The second two are sentences that represent measurements in feet and inches, like in the activity you did yesterday. The first measurement should be smaller than the second. If the number in inches is between the two measurements, inclusive, inches-in-range should return the word in-range; otherwise it should return out-of-range. Examples:

(inches-in-range 17 '(1 2) '(3 5)) should return in-range, since 17 inches is between 1' 2" and 3' 5". (inches-in-range 14 '(1 2) '(3 5)) should also return in-range, since 14 inches is exactly 1' 2". (inches-in-range 59 '(2 0) '(4 0)) should return out-of-range, since 59 inches is bigger than 4".

Use only if, the code from the measurements.scm file you wrote yesterday, and numerical comparisons to define inches-in-range. Add inches-in-range to your measurements.scm file. 6.1.6 (Display page) Practice with "and", "or", and "not". Practice with and, or, and not.

Two procedures named and and or are useful for combining true-or-false results. And, given any number of expressions, returns true if all the expressions have true values. Or returns true if at least one of its arguments is true. Both and and or evaluate their arguments one at a time from left to right. And stops evaluating when it finds a false result; or similarly stops evaluating when it finds a true result. Here are examples:

(if (and (is-monday? today) (equal? (location 'mom) 'home)) 'broccoli 'pizza)

(if (or (is-monday? today) (is-tuesday? today)) 'macaroni-and-cheese 'pizza)

One more procedure that's sometimes useful is not. Not takes one argument. If the argument's value is true, not returns #f; otherwise it returns #t. Rewrite the inches-in-range procedures from the previous step to use and (and perhaps not) rather than a nested if expression. Put the rewritten procedure into your file measurements.scm. (Note, you can have two definitions of the same procedure in your file. When the file is loaded as a whole, the second definition will be the one that

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 19 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

scheme uses). 6.1.7 (Brainstorm) Provide a good comment Provide a good comment.

Consider the following procedure.

(define (mystery a b) (if (odd? a) (if (odd? b) #f #t) (if (odd? b) #t #f) ) )

Fill in the blank in the following sentence with ten or fewer words: The mystery procedure returns #t when ______, and returns #f otherwise. 6.2 Practice with "cond".(3 steps) 6.2.1 (Display page) Here's how "cond" works. Here's how cond works.

The cond procedure provides a somewhat more convenient way to do a sequence of tests to decide what value to return. We earlier saw an example of a nested if expression:

(if (> water-temp 212) 'steam (if (< water-temp 32) 'ice 'liquid) )

This can be rewritten to use a cond as follows.

(cond ((> water-temp 212) 'steam) ((< water-temp 32) 'ice) (else 'liquid) )

The parenthesis structure of a cond is different from everything we've seen up until now. Here is how a cond is built.

(cond ( question-1 value-1 ) ( question-2 value-2 ) ... ( else value-n ) )

In the water classifying example above, question-1 was (> water-temp 212), question-2 was (< water-temp 32), value-1 was 'steam, value-2 was 'ice, and value-n was 'liquid. A cond is evaluated by evaluating the questions one after another until encountering either a condition that's true or the else. When it finds a true question, it returns the corresponding value. 6.2.2 (Display page) Experiment with "cond". Experiment with cond.

Write and test a procedure named sign that, given a number as argument, returns one of the words negative, zero, or positive depending on whether the argument is less than zero, equal to zero, or greater than zero. Use only a cond and numeric comparisons in your solution. Using the interpreter, test your procedure with inputs -1, 1, and 0. 6.2.3 (Display page) Reorganize a "cond" expression. Reorganize a cond expression.

Since a cond is evaluated by successively evaluating the condition expressions, each false value provides information that can simplify the subsequent tests. Consider an example seen earlier:

(cond ((> water-temp 212) 'steam) ; At this point, we know that water-temp is at most 212. ; Thus we don't need to check that again. ((< water-temp 32) 'ice) ; Now we know that water-temp is less than or equal to 212 ; and greater than or equal to 32. (else 'liquid) )

Rewrite the following procedure so that each condition in the cond takes advantage of all the tests that have been done before it in the cond. You should be able to remove about half of the code.

; The argument is a sentence of three integers. ; Return whichever of the words all-the-same, ; one-pair, or all-different is relevant. (define (seq-type sent) (cond ((and (= (first sent) (second sent)) (= (second sent) (third sent))) 'all-the-same) ((and (= (first sent) (second sent)) (not (= (second sent) (third sent)))) 'one-pair) ((and (= (first sent) (third sent)) (not (= (second sent) (third sent)))) 'one-pair) ((and (= (second sent) (third sent)) (not (= (first sent) (third sent)))) 'one-pair) (else 'all-different) ) ) 6.3 Devise good tests.(5 steps) 6.3.1 (Display page) Here's how to test an "if" or "cond". Here's how to test an if or cond.

We test our procedures to provide evidence that they work. Good test cases will uncover errors wherever they exist in a procedure, and thus must exercise every possibility for a procedure's return value. For an if, there are two cases, one where the test expression is satisfied, the other where it's not. Thus to test the procedure

(define (classification candy-type) (if (equal? candy-type 'chocolate) 'wonderful 'ok) ) we need at least one call where the test is satisfied, i.e.

(classification 'chocolate) and at least one where it's not, e.g.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 20 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(classification 'peanut-brittle)

For a cond, there are as many possibilities as there are question expressions. In the procedure

(define (sign x) (cond ((< x 0) 'negative) ((= x 0) 'zero) (else 'positive) ) ) there are three possibilities, so all should be tested. An example set of tests that would do this is

(sign -5) (sign 0) (sign 3) 6.3.2 (Display page) Here's how to test an "and" or an "or". Here's how to test an and or an or.

With either an and or an or, we again should test all possibilities:

true and/or true true and/or false false and/or true false and/or false If some of these are logically impossible, the number of test cases would be less. Here's an example.

; Return true if the integer argument is in the range ; from 0 to 100 (greater than 0, less than or equal to 100). (define (in-range? x) (and (> x 0) (<= x 100)) ) The cases to test are

1. x > 0 is true, x <= 100 is true 2. x > 0 is true, x <= 100 is false 3. x > 0 is false, x <= 100 is true 4. x > 0 is false, x <= 100 is false

Values in the first category are those between 1 and 100, inclusive. In the second category are values greater than 100; the third category contains 0 and negative numbers. The fourth category contains no values at all and thus doesn't need to be tested. 6.3.3 (Display page) Consider "boundary cases". Consider boundary cases.

Often programs work with numbers in a given range, for instance, in the range 1 to 100 in the previous step. Careless programmers sometimes accidentally use comparisons with < where they meant <= or vice versa, or > instead of >=. Thus one should test these boundary values in addition to the more typical values not at the ends of the range. 6.3.4 (Display page) Test supporting procedures Test supporting procedures

If one procedure you are writing relies on other smaller procedures you have written, you can't just test the big procedure and go home satisfied. As your code gets larger and you have more procedures, there are more and more places for errors to hide. The easiest way to find them is to test every procedure on its own. If you wanted to test your inch-in-range procedure, you would also need to test the other procedures in measurements.scm. There's an analogy with house building. The idea here is to make sure that the "foundation" of your program—the "building-block" procedures—is secure, via thorough testing, before adding to the building. 6.3.5 (Display page) Write a procedure and devise a set of test calls. Write a procedure and devise a set of test calls.

Write a procedure named outranks? that, given two card ranks as arguments, returns true if the first rank is greater than the second and returns false otherwise. Put your procedure in a file named outranks.scm. A rank is represented by a word that is either one of the integers 2 through 10 or one of the letters a, k, q, or j (for "ace", "king", "queen", and "jack", respectively). An ace outranks everything, followed by a king, a queen, and a jack, followed by the numbered ranks in descending order. (For example, a king outranks a jack, which outranks a 10, which outranks a 2.) If the ranks are the same, outranks? should return false. Once you have your procedure designed, test it thoroughly and design a convincing set of test calls for the next step. 6.4 Simplify your solutions.(4 steps) 6.4.1 (Display page) Here are ways to rewrite a boolean expression. Here are ways to rewrite a boolean expression.

You have a lot of freedom when you work with and, or, and not. You can use these three procedures in many different ways to get the same result. One can transform an expression that uses not and and into an expression that uses not and or, and vice versa. In particular, the expression

(and (not x) (not y)) is equivalent to the expression

(not (or x y)) for expressions x and y that both return true or false. Similarly, the expression

(or (not x) (not y)) is equivalent to the expression

(not (and x y)) Here's an example. Suppose that a gymnasium is reserved from the 4th to the 20th of every month. A procedure that says when it's reserved is

(define (reserved? date) (and (>= date 4) (<= date 20)) ) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 21 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

In English, this says it is reserved if it is both on or after the 4th and on or before the 20th. Someone wanting to use the gymnasium, however, would be more interested in when it's not reserved:

(define (free? date) (not (and (>= date 4) (<= date 20))) ) This is somewhat complicated. In English, it says that the gym is free if it is not both on or after the 4th and on or before the 20th. It can be made easier to understand by using the equivalence just described:

(not (and (>= date 4) (<= date 20))) is equivalent to

(or (not (>= date 4)) (not (<= date 20)))

The not expressions can be simplified:

(or (< date 4) (> date 20)) In English, this is is like saying the gym is free if it's before the 4th or after the 20th. 6.4.2 (Display page) Try to avoid using "not", when possible. Try to avoid using not.

Generally, it's easier to understand conditions that don't involve the use of not. Compare

(define (job person) (if (member? person '(clint alex )) 'ta-or-instructor 'lab-assistant) ) with

(define (job person) (if (not (member? person '(clint alex))) 'lab-assistant 'ta-or-instructor) ) 6.4.3 (Brainstorm) Compare "and" and "or" with "if" and "cond". Sometimes a condition is easily stated in English using and or or. For example, in fall and spring course loads of between 13 and 19 units do not require a petition:

(define (acceptable-course-load? unit-count) (and (>= unit-count 13) (<= unit-count 19)) )

Sometimes, however, it is easier to separate the cases of a condition using if or cond. Write two versions of a procedure named exactly-one?. This procedure takes two boolean arguments; it returns #t if exactly one of the arguments is true, and returns #f if either both are true or both are false. One of your versions should use one or more of and, or, and not without using if or cond. The other should use if or cond without using and, or, or not. Here are examples of how exactly- one? should work.

expression value to return (exactly-one? (= 6 4) (= 4 4)) #t (exactly-one? #t (= 4 4)) #f (exactly-one? #f (member? 'v 'aeiou) (> 5 8)) Make sure you test your code before you post it! 6.4.4 (Display page) Use "member?" to simplify comparisons. Use member? to simplify comparisons.

When you're designing a test to check whether a given word or character is one of a bunch of alternatives, it is typically better to use member? than to do all the comparisons individually. (Recall that member? tests whether its first argument is a member of its second, that is, one of the letters in a word or one of the words in a sentence.) For example, use

(define (vowel? ltr) (member? ltr '(a e i o u)) ) rather than

(define (vowel? ltr) (or (equal? ltr 'a) (equal? ltr 'e) (equal? ltr 'i) (equal? ltr 'o) (equal? ltr 'u) ) ) and

(define (weekend? day-name) (member? day-name '(saturday sunday)) ) rather than

(define (weekend? day-name) (or (equal? day-name 'saturday) (equal? day-name 'sunday) ) ) 6.5 Test your understanding.(3 steps) 6.5.1 (Display page) Write a procedure using "if" or "cond" but not "and" or "or". Write a procedure using if or cond but not and or or.

Without using and or or, write a procedure named legal?. Legal? should return #t if its argument is a two-character word that starts with a vowel and ends with a digit; it should return #f otherwise. You should make no assumptions about the argument. For example, legal? should return #f for all of the following arguments.

'(a 5) + 'abc5 "" 'a15 http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 22 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

'(x y z) ( )

Put your procedure in a file named legal1.scm. 6.5.2 (Display page) Rewrite the procedure to use "and" or "or" but not "if" or "cond". Rewrite the procedure to use and or or but not if or cond.

Now rewrite the legal? procedure to use and or or but not if or cond. Put this in a file named legal2.scm. 6.5.3 (WebScheme) Predict the behavior of "and," "or," and "if" Predict the behavior of and , or , and if

Fill in the blanks below to get the right answer. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. If you are unable to run this step, copy the definitions below to your Scheme listener and check your answers there. (Your TA can help. Use cntl-Y to paste in Emacs). Assume you have the following procedures defined:

(define (old-macdonald1? letter) (equal? letter (or 'e 'i 'o)))

(define (old-macdonald2? letter) (or (equal? letter 'e) (equal? letter 'i) (equal? letter 'o)))

Scheme Expression Value Correct?

(old-macdonald1? 'e)

(old-macdonald1? 'i)

(old-macdonald1? 'q)

(old-macdonald2? 'e)

(old-macdonald2? 'i)

(old-macdonald2? 'q)

6.6 Homework activities(5 steps) 6.6.1 (Display page) Comment on the last lab's discussions. Homework 3

There are 5 parts in this homework assignment:

1. Go back to the last homework and give thoughtful comments for the two discussion questions.

2. Answer the quiz in the following step titled "Analyze a procedure"

3. Contribute a post to the discussion "Test the legal? procedure", in a following step.

4. Contribute a post to the discussion "Compare leap year checkers", in a following step.

5. Write and submit a conditional expression, as detailed in the final step below. Instructions on how to submit this homework are included in the step.

6.6.3 (Discussion Forum) Test the "legal?" procedure Testing the legal? procedure

In lab, you programmed the legal? procedure that returns true if its argument is a two-character word that starts with a vowel and ends with a digit, and returns #f otherwise. Here, you are to devise and defend test cases for your procedure. Specifically, you should post a thorough set of test cases. Explain why you picked each case, as well as why you think they collectively would provide evidence that your code works perfectly. We're looking for tests so thorough that after running them, you could put your code into a program that someone's life depends on. For example, legal? should be so well tested that if an airplane navigation program needed to call it, you would feel safe flying on the airplane. In the next lab, we'll ask you to comment on the thoroughness or incompleteness of at least two other collections of tests that your classmates provide. A comment such as "you may have forgotten to test for ..." would be appropriate. 6.6.4 (Discussion Forum) Compare leap year checkers. Compare leap year checkers

A year in our calendar is a leap year—it has 366 days—if it is either divisible by 400 or divisible by 4 but not by 100. Thus 2000 was a leap year, 1900 was not, 1996 was, and 1999 wasn't. All of the following procedures return true if the argument year is a leap year and false otherwise. Provide a post that says which version you prefer, and why, explaining what is it that makes one easier to read. In the next lab, we'll ask you to comment on at least two other posts.

(define (is-leap-year? year) (or (is-divisible-by? year 400) (and (is-divisible-by? year 4) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 23 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(not (is-divisible-by? year 100)) ) ) )

(define (is-leap-year? year) (cond ((is-divisible-by? year 400) #t) ((is-divisible-by? year 100) #f) (else (is-divisible-by? year 4)) ) )

(define (is-leap-year? year) (if (is-divisible-by? year 4) (if (is-divisible-by? year 100) #f (is-divisible-by? year 400) ) #f) ) 6.6.5 (Display page) Write a conditional expression Writing a conditional expression

The game of "rock/paper/scissors" is played by two players. They simultaneously display "rock" (a clenched fist), "paper" (a flat hand), or "scissors" (a two-fingered "V"). If they both show the same thing, the same is a tie; otherwise, "rock" beats "scissors", "scissors" beats "paper", and "paper" beats "rock". Write and test a procedure named game-result that, given two arguments representing what player 1 and player 2 display, returns either tie, win, or loss, depending on whether the two players' choices were the same, player 1's choice beat player 2's, or player 2's beat player 1's. For example:

(game-result 'scissors 'paper)

should return win, while

(game-result 'rock 'paper)

should return loss. Your procedure should consist of calls to if, cond, and/or equal?, and it should make as few calls to equal? or member? as possible. (It is possible to do this with a total of two calls to equal? or member?, but that takes a lot of thinking. We expect most people to be able to do it with a total of seven calls. If you use more than this, you will lose some points.)

Submission instructions

Put your procedure into the file hwk3.scm in a folder called hwk3. For this and future homeworks, you will submit your file(s) electronically. Do this from within unix. Move to the hwk3 directory (cd hwk3) and type:

> submit hwk3

You should then be asked several questions by the submit program regarding which files to send (depending on the names of files within the directory). It is crucial that your homework file be named hwk3.scm exactly for the submit program to automatically find it. It is also necessary that you invoke the submit hwk3 command from within the hwk3 directory, where hwk3.scm resides. Note that the other files you created in this lab should not be submitted as homework. 7 Putting conditionals and words and sentences together 2009-9-08 ~ 2009-9-09 (5 activities) 7.2 Use good names and provide good comments.(2 steps) 7.2.1 (Display page) Programs should read like English. Programs should read like English.

Programs are written partly to be run; that's how work gets done with the computer. The Scheme interpreter will run your program regardless of the names you use for procedures and placeholders. For example,

(define (foo q) (* q q) ) is understood by the Scheme interpreter to be the same thing as

(define (square num) (* num num) ) Programs are also written to be read by people, however. People might include your instructor or supervisor, your project partner, or even yourself (reading a program a couple of months after you wrote it, and trying to figure out what you meant). Good choices for procedure and placeholder names, as well as good use of comments, can make it significantly easier for someone to understand how to use your program, what it's supposed to do, and how to modify it if necessary.

Adding comments to your code

Comments start with a semicolon, and are completely ignored by the Scheme interpreter. It is good practice to make an entire line a comment; that is, start the line with a semi-colon. (There are other ways to specify comments we will talk about later). Because comments are ignored by Scheme, they are only relevant for someone reading the program. Programmers typically accompany each procedure they write with a comment that says what the procedure expects as arguments and what it will return for given arguments. Examples of how a procedure is supposed to behave are good to include as part of the explanation. Here is a sample procedure with some comments:

;;square: takes a number and squares it ; note: don't use it with anything except numbers ; written by: clint, 18 June 2003 (define (square num) (* num num))

Choosing good names for procedures and variables

Good choices for names depend on the situation. For parameters, a good name gives some idea of the type of value it represents for example, num in the square procedure above. This name explains that you're not expecting to multiply a word by itself. Typically, the name of a procedure that returns a number, a word, or a sentence is a noun that represents the value returned. The name of a predicate procedure one that returns true or falseis conventionally an verb. This is because such procedures are typically used with if, for example:

(if (is-legal? x) ... ) (if (is-number? x) ... ) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 24 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(if (is-word? x) ... ) The built-in predicates are not always named as well as they could be. One always has to balance information communicated by a name with the length of that name (a name that's 100 characters long won't be very readable!), and the designers of Scheme valued conciseness a bit more than readability. 7.2.2 (Brainstorm) Provide a good name for a procedure Here's a mystery procedure written by a programmer who chose terrible names. Provide a good comment for the procedure and replace its names with words that communicate much better what the procedure does. Check your labmates' answers. Did they make the code really easy to understand? Are there comments that don't really explain the code?

; useless comment (define (x y) (word 'un y) ) 7.3 Use helper procedures.(6 steps) 7.3.1 (Display page) Helper procedures can make a program more understandable. Helper procedures can make a program more readable and more writable.

The built-in procedures first, butfirst, sentence, and word are named well enough to tell the reader of a program what it's doing, but not why. Here's an analogy in real life of how terms at this level of detail might not be the best possible way to communicate:

You (to your friend): What are you doing? Your friend, responding in obnoxious low-level terms: I'm typing an 's'. Now I'm typing an 'e'. Proper answer: I'm doing my CS 3 homework. A good programmer often defines procedures that don't do much other than provide a good high- level name for a low-level operation. For example, when working with the programs in measurements.scm, you might define helper procedures named feet and inches and use them instead of first and second. Helper procedures are also useful when writing a procedure in the first place. Often a programmer can see how to solve some part of the problem, and writes a helper procedure to do this. Naming that helper procedure can help with designing the rest of the complete procedure to design (and also make the whole solution more readable). 7.3.2 (Display page) Analyze and simplify a procedure by defining helper procedures. Analyze and simplify a procedure by defining helper procedures.

Here's a procedure that checks whether its arguments represent a valid date in the Gregorian calendar (the one we use in the United States). Simplify it and make it more readable by defining and using well-named helper procedures. When you are done, there should be more code than when you started, but it should be easier to understand. Put you new code, with helper functions, in a file called legal-date.scm.

; Return true if the arguments represent a legal date ; in the Gregorian calendar (instituted at the end of 1582). ; (Dates in the future are legal.) (define (valid-date? day month year) (cond ((or (< day 1) (> day 31) (< month 1) (> month 12) (<= year 1582)) #f) ((= day 31) (member? month '(1 3 5 7 8 10 12))) ((= day 30) (not (= month 2))) ((and (= day 29) (= month 2)) (cond ((divisible? year 400) #t) ((divisible? year 100) #f) ((divisible? year 4) #t) (else #f) ) ) (else #t) ) )

(define (divisible? num1 num2) (= 0 (remainder num1 num2))) 7.3.3 (Display page) Compare your helper procedures with others. There are many different ways to break down the valid-date? program using helper procedures. Share your code with someone else in the class. Which code do you think is easiest to read and understand? Which do you think is the hardest to read? 7.3.4 (Brainstorm) What did you see? What makes code easy or hard to understand? What will you do to make your own code easier to read? 7.3.5 (Display page) Now test it Test it to death

When programmers simplify code, it is easy to break the code they are supposed to be simplifying. To address this problem, what programmers do in industry is run a ton of tests on the old program and the new program to make sure they do the same thing Give your code a serious testing! When you think you are done, trade code with another group to see if you can break each other's simplified version. What test cases can you think of that the other group might not have. Make sure to explain any bugs you caught in the other team's code. 7.3.6 (Display page) Using comments to include test cases in your files The Scheme interpreter that we use has another way to include comments: surrounding text by #| (at the beginning) and |# at the end. The interpreter will ignore anything within these tags. (Most Scheme dialects know about this comment method, but not all do). Although less simple to use than starting a line with a semicolon, these comments can span multiple lines. As such, they are a convenient way to include test cases in the same file as the procedure you wish to test. For example:

;; Square: takes a number and returns its square ; written by Clint, 18 June 2003 (define (square num) (* num num))

#| Test Cases for square

; should return 9 (square 3) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 25 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

; should return 9 (square -3)

; should give an error (square 'three)

|# By including the test cases inside a multi-line comment, they will not be evaluated when the entire file (or emacs buffer) is loaded. However, you can easily copy the individual test cases (or all of them) from your file into your Scheme listener and run them—simply copy the text just inside the comment tags #| and |#. Adding semicolon comments within a multi-line comment, which is not necessary when the whole file is evaluated, makes copying the test cases easier. 7.4 Write larger procedures.(2 steps) 7.4.1 (Display page) Write an answer procedure. Write an answer procedure. (This will be part of your homework for this lab).

Write a procedure named answer that, given a sentence that represents a question, returns a simple answer to that question. (A question's last word ends with a question mark.) If the argument sentence is not a question, answer should merely return the argument unchanged. Here's how the answer procedure should process different kinds of questions.

Given ( am i ...? ), answer should return ( you are ...). Given ( are you ...? ), answer should return ( i am ...). Given ( some-other-word i ... ? ), answer should return ( you some-other-word ...). Given ( some-other-word you ... ? ), answer should return ( i some-other-word ...). Given any other question, answer should return the result of replacing the question mark by a period.

IMPORTANT: Scheme has some problems with periods. (More correctly, a period means something special in Scheme, and different than punctuation that comes at the end of a english sentence.) You need to put a period in double quotes ("). For example, if you want to put a period at the end of the word "weasel," you would use this code: (word 'weasel ".")

For your homework you will put your solution, along with a comprehensive set of test calls for each procedure, into a file named answer.scm inside the lab4 directory. Make sure to use good names and helper procedures to make your program as readable as possible. For this program, you should feel free to collaborate in the initial stages. It will be turned in and graded, but we will be more lenient about collaborative work for this assignment. Certainly, work with your fellow students to understand the problem, and to break it down into logical pieces. You can work together on some of the coding, but you should do the majority of the coding individually. If some of the coding is shared, note with a comment what was shared and with whom. 7.4.2 (Display page) Write a time-of-day procedure. Write a time-of-day procedure.

Write a procedure named time-of-day that, given a non-negative integer that represents the number of minutes after midnight for that day, returns the time of day in the format described below. Put this procedure, along with a comprehensive set of test calls, in a file named daytime.scm. There are several cases for the format of a time of day.

Noon and midnight are represented by the words noon and midnight respectively. An afternoon time (between noon and midnight) should be represented by a sentence whose second word is pm and whose first word has the form hours:minutes, where hours is between 1 and 12 and minutes is a two-digit number of minutes. An example: (7:05 pm). Similarly, a morning time should be a two-word sentence whose second word is am and whose first word has the form hours:minutes.

One way to get started on a big program like this is to try to write some helper procedures. Here are some suggested helper procedures - You may not need all of them, but they will probably be a good way to get warmed up. Can you think of any others you might want?

;; Use the number of seconds to get the hour of that day. ;; It will return a number between 0 and 23. (define (number-of-hours seconds) ... ) ;; Use the number of seconds to get the minutes past the hour ;; It will return a number between 0 and 59. (define (number-of-minutes seconds) ... ) ;; Returns #t if the seconds provided represents noon. (define (is-noon? seconds) ... ) ;; Returns #t if the seconds provided represents midnight. (define (is-midnight? seconds) ... ) ;; Returns #t if the seconds provided represents an AM time. (define (is-AM-time? seconds) ... ) ;; Returns #t if the seconds provided represents a PM time. (define (is-PM-time? seconds) ... )

Note: Don't worry if your answer comes out surrounded by double quotes (like "7:05" instead of 7:05). If you want to get rid of decimal points after numbers, you can use the inexact->exact procedure. As an example, (inexact->exact 1.0) returns 1. 7.5 Homework(2 steps) 7.5.1 (Display page) Homework for next session Homework

1. Read the "Difference Between Dates" case study, part I. (It is crucial that you read this before coming to the next two lab sessions!) 2. Go back to the last homework's discussion activities and for each, make two thoughtful comments on other people's posts. 3. You will need to complete the first part of this homework before doing this step. CS 3 students sometimes ask, "Why did you bother with showing us the dead-end solution? Why not just show us the 'right' solution?" What do you think about that? Contribute a post to this http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 26 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

question in the step titled "Comment on seeing 'bad' solutions". 4. Write answer.scm, as detailed in an earlier step. Be sure to include comprehensive tests. Submit this program by: From within unix, moving to the lab4 directory, or wherever you put answer.scm. Typing submit hwk4. It is crucial that your file be named answer.scm !

7.5.2 (Discussion Forum) Comment on seeing "bad" solutions. The first solution presented in the "Difference Between Dates" case study was a dead end. Is it a good idea to study "bad" solutions? Provide an answer and an explanation. Next homework, we will ask you to comment on the answer of one of your classmates. 8 "Difference between Dates" case study 2009-9-10 ~ 2009-9-11 (3 activities) 8.1 Work with version 1 of the case study programs.(9 steps) 8.1.1 (Evidence) Here's the version 1 code. If you want to open this code in another window, click here

;; Return the difference in days between earlier-date and ;; later-date. earlier-date and later-date both represent ;; dates in 2002, with earlier-date being the earlier of ;; the two dates. ;; Note: general-day-span is not implemented. (define (day-span earlier-date later-date) (cond ((same-month? earlier-date later-date) (same-month-span earlier-date later-date) ) ((consecutive-months? earlier-date later-date) (consec-months-span earlier-date later-date) ) (else (general-day-span earlier-date later-date) ) ) )

;; Selector procedures for the components of a date. (define (month-name date) (first date)) (define (date-in-month date) (first (butfirst date)))

;; Return true if date1 and date2 are dates in the same ;; month, and false otherwise. Date1 and date2 both ;; represent dates in 2002. (define (same-month? date1 date2) (equal? (month-name date1) (month-name date2)))

;; Return the number of the month with the given name.

(define (month-number month) (cond ((equal? month 'january) 1) ((equal? month 'february) 2) ((equal? month 'march) 3) ((equal? month 'april) 4) ((equal? month 'may) 5) ((equal? month 'june) 6) ((equal? month 'july) 7) ((equal? month 'august) 8) ((equal? month 'september) 9) ((equal? month 'october) 10) ((equal? month 'november) 11) ((equal? month 'december) 12) ) )

;; Return true if date1 is in the month that immediately ;; precedes the month date2 is in, and false otherwise. ;; Date1 and date2 both represent dates in 2002. (define (consecutive-months? date1 date2) (= (month-number (month-name date2)) (+ 1 (month-number (month-name date1))) ) )

;; Return the difference in days between earlier-date and ;; later-date, which both represent dates in the same month ;; of 2002. (define (same-month-span earlier-date later-date) (+ 1 (- (date-in-month later-date) (date-in-month earlier-date)) ) )

;; Return the number of days in the month named month. (define (days-in-month month) (cond ((equal? month 'january) 31) ((equal? month 'february) 28) ((equal? month 'march) 31) ((equal? month 'april) 30) ((equal? month 'may) 31) ((equal? month 'june) 30) ((equal? month 'july) 31) ((equal? month 'august) 31) ((equal? month 'september) 30) ((equal? month 'october) 31) ((equal? month 'november) 30) ((equal? month 'december) 31) ) )

;; Return the number of days remaining in the month of the ;; given date,including the current day. Date represents a ;; date in 2002. (define (days-remaining date) (+ 1 (- (days-in-month (month-name date)) (date-in-month date) ) ) )

;; Return the difference in days between earlier-date and ;; later-date, which represent dates in consecutive months ;; of 2002. (define (consec-months-span earlier-date later-date) (+ (days-remaining earlier-date) (date-in-month later-date))) 8.1.2 (Display page) Draw a call tree. Draw a call tree http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 27 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

A call tree for a program is a diagram that contains the names of all the program's procedures, with an arrow from one procedure name to another if the first procedure calls the second. Here, for example, is a call tree for version 2 of the "Difference Between Dates" code.

day-span | | v day-of-year / | \ / | \ v | \ days-preceding | \ v \ month-name v date-in-month On paper, draw a call tree for the version 1 program, and show it to your t.a. 8.1.3 (WebScheme) Provide calls to day-span that return given values. Provide calls to day-span

Fill in the first row of blanks below with legal dates that, when input to version 1 of day-span, produce a result of 45. Fill in the second row of blanks with legal dates that produce a result as large as possible. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. If you miss any of these, put an entry in your notebook explaining the reason you missed it. day- day-span call span Correct? result

(day-span ' ' ) ????

(day-span ' ' ) ????

8.1.4 (WebScheme) Provide another call to day-span that results in a call to day-remaining. Provide a call to day-span

Fill in the blanks below with legal dates that, when input to version 1 of day-span , produce a call to days- remaining . day-span call Correct?

(day-span ' ' )

If you miss this question, put an entry in your notebook explaining the reason you missed it.

8.1.5 (Display page) What's the result of giving invalid dates to day-span? The next three questions ask about the effect of calling day-span with invalid dates—dates that have either an invalid month or an invalid date-in-month. Assume for each question that one of the dates is incorrect as indicated and the other is correctly formatted. 8.1.6 (WebScheme) Identify where an invalid month name would cause a crash. Analyze the effect of providing a date with an invalid month name to day-span

When we evaluate (day-span '(may 1) '(jun 5)) using version 1 of the days-span procedure in our Scheme interpreter, the following message appears:

Bad number in a comparison: (okay)

This is an error message generated by the = procedure. Please answer the following questions (after waiting for SchemeHandler to appear in the upper-left corner). question your answer correct? Is the okay being supplied as the first input (type 1 in the box) or the second (type 2 in the box)? In which procedure defined in the version 1 code is the call that resulted in the error message? Now consider the result of evaluating

(day-span '(mey 1) '(june 5))

and answer the following questions. question your answer correct? Fill in the name of the procedure in the error message that : not a number: okay results. (Which procedure produced the error message?) In which procedure http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 28 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

procedure defined in the version 1 code is the call that resulted in the error message? If you miss any of these questions, put an entry in your notebook explaining the reason you missed it.

8.1.7 (WebScheme) Identify where an invalid date-in-month would cause a crash. Analyze the effect of providing a date with a nonnumeric date-in-month to day-span

Before continuing, experiment in the interpreter with calls to day-span in which one of the arguments has an invalid date-in-month, for example (january x) Alternatively, you may experiment by typing dates in the line below and clicking on the pointer.

(day-span ' ' ) try it

What you should be looking for is the same information you noticed in the previous step: the name of the builtin procedure whose call directly produces a crash-- = or + in the previous step--and the name of the procedure defined in the program that contains the call. Please fill in the table below with all possibilities for these two procedures. (There are between 1 and 5.) Then click the "test-all" button to check your answers. test all all builtin procedure whose call procedure in day-span correct? possibilities produces the error that calls it found?

If you miss any of these questions, put an entry in your notebook explaining the reason you missed it.

8.1.8 (Brainstorm) Explain why the two arguments might be handled differently. You have just noticed that a call to day-span with an invalid first argument might result in a crash in one part of the program, while a call to day-span with an invalid second argument might produce a crash in a different part of the program. Why don't the two situations act the same? 8.1.9 (Brainstorm) What if the date-in-month is an invalid integer? List all possible consequences or return values that can result from a call to day-span with one of the arguments containing an integer date-in-month that's not legal (Assume that the other argument is correctly formatted.) Here's an example.

(day-span '(january 400) '(february 3)) If an error message results, identify the procedure that produced it. Be sure to review the brainstorm responses after a while to ensure that you haven't missed any of the possibilities. 8.2 Work with version 2 of the case study programs.(6 steps) 8.2.1 (Evidence) Here's the version 2 code. If you would like to get this code in another window, click here.

;; Selector procedures for the components of a date. (define (month-name date) (first date)) (define (date-in-month date) (first (butfirst date)))

;; Return the number of days from January 1 to the first day ;; of the month named month. (define (days-preceding month) (cond ((equal? month 'january) 0) ((equal? month 'february) 31) ((equal? month 'march) 59) ((equal? month 'april) 90) ((equal? month 'may) 120) ((equal? month 'june) 151) ((equal? month 'july) 181) ((equal? month 'august) 212) ((equal? month 'september) 243) ((equal? month 'october) 273) ((equal? month 'november) 304) ((equal? month 'december) 334) ) )

;; Return the number of days from January 1 to the given ;; date, inclusive. Date represents a date in 2002. (define (day-of-year date) (+ (days-preceding (month-name date)) (date-in-month date)) )

;; Return the difference in days between earlier-date and ;; later-date. Earlier-date and later-date both represent ;; dates in 2002, with earlier-date being the earlier of ;; the two. (define (day-span earlier-date later-date) (+ 1 (- (day-of-year later-date) (day-of-year earlier-date) ) ) ) 8.2.2 (WebScheme) Produce a call to day-span that returns a given value. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 29 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Provide a call to day-span

Fill in the blanks below with legal dates that, when input to version 2 of day-span , produce a result as large as possible. To see if you are right, press the arrow. If you see a green check, you got it. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. If you miss this, put an entry in your notebook explaining the reason you missed it. day- day-span call span Correct? result

(day-span ' ' ) ????

8.2.3 (WebScheme) What's the result of giving invalid dates to day-span? Analyze the effect of providing an invalid date to day-span version 2

Before continuing, experiment in the interpreter with calls to day-span in which one of the arguments has an invalid month name, for example (mike 31) Alternatively, you may experiment by typing dates in the line below and clicking on the pointer.

(day-span ' ' ) try it

What you should be looking for is the same information you noticed in earlier experiments: the name of the builtin procedure whose call directly produces a crash, and the name of the procedure defined in the program that contains the call. Please fill in the table below with all possibilities for these two procedures. (There are between 1 and 3.) Then click the "test-all" button to check your answers. test all all builtin procedure whose call procedure in day-span correct? possibilities produces the error that calls it found?

Now do the same for a date with an invalid date-in-month, for example, (may x) There are between 1 and 3 possibilities for the crash location. test all all builtin procedure whose call procedure in day-span correct? possibilities produces the error that calls it found?

If you miss any of these questions, put an entry in your notebook explaining the reason you missed it.

8.2.4 (WebScheme) Implement wraparound-day-span. Implement wraparound-day-span

One may find through experimenting that supplying date arguments that are legal but out of order (i.e. with the later date as the first argument) does not crash the program. Here is a table of sample calls. day-span call result (day-span '(may 2) '(may 1)) 0 (day-span '(may 3) '(may 1)) -1 (day-span '(may 1) '(april 1)) -29 (day-span '(december 31) '(january 1)) -363 It would be nice if the program could handle these dates "correctly", that is, by "wrapping around" from one year to the next. We ought to be able to ask a more general procedure named, say, wraparound-day-span to handle dates in either order. Given dates in order, wraparound-day-span should just return what day-span returns. Given dates out of order, it should interpret the second argument as being a date in the next year, and return an appropriate result. Examples: wraparound-day-span call result (wraparound-day-span '(may 1) '(may 1)) 1 (wraparound-day-span '(april 30) '(may 1)) 2 (wraparound-day-span '(january 1) '(december 31)) 365 (wraparound-day-span '(may 2) '(may 1)) 365 (wraparound-day-span '(may 3) '(may 1)) 364 (wraparound-day-span '(may 1) '(april 1)) 336 (wraparound-day-span '(december 31) '(january 1)) 2 Fill in the blanks in the procedure framework below to complete the implementation of the wraparound-day- span procedure. Click on the hand to run the tests in the table above. There are many ways to solve this problem, but most will not fit in the space provided. It's important for you to find a short way that fits in the blanks. framework run tests result (define (wraparound-day-span date1 date2) (if (day-span date1 date2) ; dates are in order ) )

wraparound-day-span call desired result your result http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 30 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(wraparound-day-span '(may 1) '(may 1)) 1 ???? (wraparound-day-span '(april 30) '(may 1)) 2 ???? (wraparound-day-span '(january 1) '(december 31)) 365 ???? (wraparound-day-span '(may 2) '(may 1)) 365 ???? (wraparound-day-span '(may 3) '(may 1)) 364 ???? (wraparound-day-span '(may 1) '(april 1)) 336 ???? (wraparound-day-span '(december 31) '(january 1)) 2 ???? If you miss any of these, put an entry in your notebook explaining the reason you missed it.

8.2.5 (Brainstorm) Find a bug. Your little brother or sister changes a single word, integer, or symbol in the second version of the day-span program, with the result that the call

(day-span '(february 1) '(march 1)) returns 30 instead of the correct answer 29. List two different causes of the bug, that is, substitutions of a single word, integer, or symbol that would produce the behavior described. (We think there are at least three.) 8.2.6 (Brainstorm) Describe how you found the two bug possibilities. Describe how you figured out, in the previous step, where the bugs might be. 8.3 Homework(5 steps) 8.3.1 (Display page) Provide comments for the last homework's discussions Go back to the last homework discussion assignment Comment on seeing "bad" solutions. Give at least one thoughtful response to another student's answer. 8.3.2 (Display page) Write day-span to handle leap years. Produce two versions of day-span that work for dates in a leap year. Name them leap-day-span and put them into the files LY1-day-span.scm and LY2-day-span.scm in your hwk5 directory. (You will need to create the hwk5 directory). Both versions should assume that the arguments are legal dates in a leap year (e.g. 2000), with the first argument coming at or before the second argument as in the case study programs. When you want to add new features to a program that is already written, you have two choices. Your first choice is to edit part(s) of the existing the code. This works well if you understand all of the details about how the code works. Your second choice is to leave the original code alone and write new code that reuses the old code. This works well if you don't understand the details of how the old code works, as long as you know how to use the old code.

For the first version, you should edit the old code. Rename the good day-span procedure (from Appendix B of the case study) to leap-day-span and modify one or more of its helper procedures. The structure of the program should be the same as the program described in the case study; that is, a call to leap-day-span should result in calls to day-of-year, days- preceding, etc. in the same way as a call to the original day-span does. For the second version, you should keep the old code the same and write new code that reuses old code to get the right result. Don't modify the original day-span at all. Instead, your leap-day-span should send its arguments to the existing day-span and decide separately whether or not to add 1 (for February 29) to the value it returns.

Both versions of leap-day-span should use the good version of the day-span code (version 2). You can find that in Appendix B of the case study. Include a set of convincing tests in your solution files. This assignment is due the beginning of next lab. 8.3.3 (Display page) Identify three possible causes of a bug. Your pesky younger brother or sister changes a single word, integer, or symbol in the first version of the day-span program, with the result that the call

(day-span '(january 1) '(february 1)) returns 1 instead of the correct answer 32. List three different potential causes of the bug, that is, substitutions of a single word, integer, or symbol that would produce the behavior described. Also explain why each of your substitutions would cause the bug. Put your list of possible bugs and your explanations in a file named bug.possibilities in your hwk5 directory. We think there are at least four possibilities for the changed word, integer, or symbol. 8.3.4 (Display page) Don't forget to submit the homework When you have completed all three files, submit them. Remember:

1. The files will have to be named exactly as specified in the lab. 2. You submit the files from unix. 3. You will need to be inside the hwk5 directory (you can type cd ~/hwk5 to ge there). 4. Submit the files with a hearty "submit hwk5".

8.3.5 (Discussion Forum) Devise three exam questions. Devise three exam questions that would evaluate a student's understanding of the case study and the case study code. Next lab, you will be asked to (politely) suggest improvements to the questions of two of your classmates. 9 Review of the first two weeks. 2009-9-10 ~ 2009-9-11 (2 activities) 9.1 Summary(2 steps) 9.1.1 (Display page) Big ideas We covered quite a bit of territory in the first two weeks. You may have spent most of your time learning how to format Scheme code, how to use emacs, how to use unix, and so forth. But, there are several big ideas that we've introduced in the first four days, and we'll come back to these again and again over the course of the semester.

Big ideas

How scheme evaluates input Words and sentences Conditionals, predicates, and boolean values Testing Writing good code (choosing good names, writing comments, using helper procedures) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 31 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

9.1.2 (Display page) The programs and files that you created Programs (and files) that you have worked on

Day 1:

square sales-tax (sales.scm) discount-price (sales.scm) selling-price (sales.scm) day-of-year fifteen, identity, and others for homework additional files in the Emacs tutorial

Day 2:

inch-count (measurements.scm) height (measurements.scm) FR-date (FR-date.scm) insert-and, for homework

Day 3:

next-higher-even (if-tests.scm) non-crashing-first (if-tests.scm) smaller (if-tests.scm) inches-in-range (measurements.scm) sign seq-type, reorganization exactly-one?, two different versions legal? (legal2.scm). Also, homework was to add tests game-result, for homework

Day 4:

comfort-level, in the quiz valid-date? (legal-date.scm), reorganization answer (answer.scm), for homework

9.2 Review problems(4 steps) 9.2.1 (Display page) You may not want to do these now... The following are problems designed to help you review the first two weeks of materials in the course. It might be wise to save some of these for a later date (say, while studying for midterm 1). Plus, there is a good chunk of materials on the Differences between Dates case study for you to work on! 9.2.2 (Display page) Practice with these "tricky" questions... Review of Days 1-4, Self Test

Below are four links. Each will take you to another page with some questions and, after you answer, explanations on why your answer is correct or incorrect.

Exercises on and

Exercises on or

Exercises on cond

is-leap-year? revisited

Changing cond cases in valid-date?.

9.2.3 (Display page) What comes between? From CS3 spring 2006 Midterm 1 Problem X. (A: 3 points, B: 3 points, C: 4 points) What comes between? Write a procedure called between? which takes three numbers as arguments, and returns true if and only if the second argument is between and not equal to the first and the third: (between? 5 6 7) --> #t (between? 7 6 5) --> #t

Part A: Write between? without using if or cond.

Part B: Write between? without using and or or.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 32 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Part C: Write a suite of test cases for between?. Make sure you test the possible sets of parameters exhaustively as possible, in order to test different ways the code could be written. Also, make sure you describe what the result of the call should be! 9.2.4 (Display page) What comes between? (solutions and standards) What comes between? was an exam question from an earlier CS3 semester. Check here (pdf) for solutions and standards given out then. 10 Miniproject 1: Century-day-span 2009-9-15 ~ 2009-9-23 (1 activity) 10.1 Extend the "day-span" procedure to handle dates in different years.(2 steps) 10.1.1 (Display page) Here are the miniproject details. This miniproject is due Wednesday, September 23 at 11:59pm if you are in a TuTh section, and on Thursday, September 24 at 11:59pm if you are in a WF section. You may work with one other person, who must be in your lab section.

Background

The "Difference between Dates" case study dealt with the problem of finding the number of days between two dates in the same year. For this assignment, you will solve a more general problem, that of finding the number of days between two dates in different years. (You can use the code you write to find out how many days old you are.)

Problem

Write a procedure century-day-span that takes two dates as arguments, and returns the number of days between them, including the argument dates themselves. Assume that the first argument date is earlier than the second. Each date is a three-word that represents a legal date between January 1, 1900 and December 31, 2999. The first word is a month name (one of january, february, ..., december). The second is an integer between 1 and the number of days in the specified month, inclusive. The third is an integer between 1900 and 2999, inclusive; it represents a year in the 20th, 21st, 22nd, 23rd, 24th, 25th, 26th, 27th, 28th, 29th, or 30th century. Your procedure must be able to deal with leap years. A leap year between 1900 and 2999 is any year that's divisible by 400, or by 4 and not by 100. (Thus 2000 was a leap year and 1900 was not.) A leap year's February has 29 days rather than 28, and therefore it has 366 days rather than 365.

Examples

The table below lists some sample calls to century-day-span and the desired return values. expression desired return value (century-day-span '(january 3 1990) '(january 9 1990)) 7 (century-day-span '(march 30 1989) '(february 2 1990)) 310 (century-day-span '(january 1 1984) '(january 1 1985)) 367 (century-day-span '(january 1 2001) '(january 1 2005)) 1462

Miscellaneous requirements

You should write helper procedures and call them from century-day-span, rather than doing all the computation in century-day-span itself. Restrict your use of Scheme to material covered in Simply Scheme chapters 3 through 6. Test your century-day-span procedure at least on the following:

dates in the same month; dates in the same year in different months; dates in different years, where the month of the first date precedes the month of the second date; dates in different years, where the month of the first date follows the month of the second date; dates in different years that do not span a "leap day"; dates in different years that span a "leap day"; dates that span the leap day in the year 2000; dates that span the non-leap day in the year 1900; dates in different years with the first date in a leap year; dates in different years with the second date in a leap year; dates in different years with both dates in a leap year.

(Note that these are not guaranteed to reveal all your bugs.) Test your helper procedures individually. Put your century-day-span procedure and its helper procedures in a file named c.day- span.scm in your mp1 directory. ("mp" stands for "miniproject". You'll need to create this directory.) Include your tests for the century-day-span proceedure in a separate century-day-span- tests.scm. Please add comments for each test case block. If you don't want to do the math to test your code, you can go here instead. However, you will need to add 1 to every answer it gives you.

Submission details

Submit your file electronically in the usual way (i.e., within unix enter the mp1 directory, perhaps via cd ~/mp1, and then type submit mp1). 10.1.2 (Display page) Using the testing framework Testing your code

For this project, you will be using some simple procedures to help you more easily create and manage your tests. Your tests will consist of a set of test cases, where each test case contains:

a Scheme expression— this is a call to the procedure that you want to test, with arguments that will check a specific aspect of its functionality. an expected return value—this is what the scheme expression should return if it is operating http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 33 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

correctly. a name—so you can identify the particular test case when it is listed in a report.

You are expected to create test cases for the century-day-span procedure as well as its helper procedures.

Using the testing framework:

You will be using a new testing framework to test your code. There are three functions you need to know:

(add-test-case test-name expected-return-value scheme-expression) (run-test-cases) (clear-test-cases)

add-test-case

add-test-case takes in a quoted name, the return value you expect expect to get when evaluating the testing expression, and the scheme expression itself. Each test case you add needs to have a unique name; add-test-case will warn you if the name is not unique. The first argument must be quoted—it is simply a name. The second argument may or may not be quoted: if you want to give a specific word or sentence as an expected value, you need to quote this. If you want evaluate some expression to give the expected value, then it shouldn't be quoted. The third argument should never be quoted in practice -- this is the scheme expression that you want evaluated. Remember, quote things that are names or specific words/sentences; don't quote things that need to be evaluated. STk> (add-test-case 'same-month-test 1 (century-day-span '(january 1 1950) '(january 2 1950))) okay STk> (add-test-case 'century-test-1 1462 (century-day- span '(january 1 2001) '(january 1 2005))) okay run-test-cases run-test-cases will run all the test cases you added using add-test-case. STk> (run-test-cases) (----- Running 3 tests... Failure output below. -----) (----- Done. 0 failed test(s). 0 error(s). -----) okay If your test cases contain cases that generate errors or return values other than the expected value, they will be listed in the report: STk> (run-test-cases) (----- Running 3 tests... Failure output below. -----) nine ERROR: on show-hundreds (----- Done. 1 failed test(s). 1 error(s). -----) okay In the above report, the test case named nine didn't return its expected value, and the test case named show-hundreds generated an error when it was run (and, therefore didn't return any value!). clear-test-cases clear-test-cases erases all the test cases that you have currently added. STk> (clear-test-cases) okay

Setting up and running your tests You will create the file century-day-span-tests.scm to hold all of the test cases that you generate for this project. (Note, this is a different style than was discussed earlier, where tests were included directly after the definition of a procedure.) Put a comment at the top of your testing file describing it, and immediately after include the expression (clear-test-cases). This ensures that, every time the file is loaded, you start with an empty set of test cases. Next, include groups of test cases for each procedure that you want to test. Put a comment at the top of the group stating what procedure it is for and anything special you need to remember. Below the comment, add your test cases with appropriate calls to add-test-case. For example, a testing file might look like:

;;century-day-span-tests.scm

(clear-test-cases) ;;MAKE SURE THIS IS INCLUDED AT THE TOP OF YOUR FILE

;;century-day-span test cases (add-test-case 'example1 7 (century-day-span '(january 3 1990) '(january 9 1990))) (add-test-case 'example2 310 (century-day-span '(march 30 1989) '(february 2 1990))) (add-test-case 'example3 367 (century-day-span '(january 1 1984) '(january 1 1985))) (add-test-case 'example3 1462 (century-day-span '(january 1 2001) '(january 1 2005))) Once you have written your test file, send all the definitions to STk by using the Send Buffer command in emacs. Finally, you can use (run-test-cases) from within STk to test your program. As you make changes to the code, use (run-test- cases) to check that you haven't broken anything that used to work! If you add more test cases, simply reload the Emacs buffer containing your test cases. 11 More on the "Difference between Dates" case study 2009-9-15 ~ 2009-9-16 (4 activities) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 34 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

11.2 Analyze a claim about the program.(1 step) 11.2.1 (Brainstorm) Can arguments to + in version 2 of day-span be nonnumeric? A pair of CS 3 students are experimenting with version 2 of the day-span code. In one of their experiments, they called day-span and got an error message saying that the + procedure is being called with a nonnumeric argument. They believe that the crash is in the call to + in the day-span procedure rather than the call to + in day-of-year. Do you believe them? Why or why not? 11.3 Modify the programs.(5 steps) 11.3.1 (Brainstorm) Experiment with the "item" procedure. The builtin item procedure takes two arguments: an integer and a sentence or word. Describe, as completely as possible, what arguments you can give item so that it won't crash. Also say what item returns, given the arguments you just described. 11.3.2 (Brainstorm) How would the "item" procedure be useful in the case study programs? Identify all the procedures in the case study programs (both versions) that could be significantly shortened by use of the item procedure. Write the shortened code to one of these procedures using item. 11.3.3 (Display page) Make day-span work for dates in European format. In Europe, dates are specified with the date-in-month preceding the month, for example, "3 April" rather than "April 3". Define a procedure named europe-day-span whose arguments are dates in European format, that is, with the date-in-month preceding the month name rather than following it. (Assume that month names are those of English: January, February, etc.) Thus the call

(europe-day-span '(1 january) '(15 may)) should produce the same result as

(day-span '(january 1) '(may 15))

Write your procedure by modifying the code of the second version of day-span (appendix B). You will need to define a europe-day-span procedure; do this without calling the original day-span procedure. You can change any of the other helper procedures, but change as few as possible. Put your solution into the file europe-day-span.scm. In the modified version, the day-span procedure won't work correctly any more. You might want to save a copy of your modified day-span procedure that you've been working on. 11.3.4 (Display page) Data abstractions make some changes easier. Implementing the europe-day-span procedure should have required only a few changes to the rest of the program. This was no accident; the program was designed to insulate as much of the code as possible from how a date is represented. This is done by viewing a date in most of the program as an abstraction with a month name and a date-in-month rather than (say) as a two-word sentence. It's not too hard to think of real-life data abstractions. Here are some examples:

Most of us view an automobile as an abstraction with an ignition switch, a steering wheel, a gas pedal, and a brake pedal. Different cars have different internal mechanisms—disc vs. drum brakes, four vs. six vs. eight cylinders, etc.—but drivers generally need not concern themselves with the differences. Speakers in a stereo system are an abstraction with a place to plug them into the sound source. There are a variety of technologies for speakers, but someone plugging them into a stereo receiver doesn't have to worry about that. An apartment is an abstraction with (among other things) a thermostat. Apartment dwellers don't need to know whether their heating system uses gas, electricity, or whatever; they just turn up the thermostat and gets warmer.

Data abstractions are convenient for the user, but even more convenient for the programmer. Program maintenance tasks often involve changing the internal representation of some of the data, and the programmer wants this task to be as easy as possible. If the details of the representation are hidden in just a few procedures, a change to the representation should require changing only those procedures; the rest of the program shouldn't need modification. In the Difference Between Dates programs, the representation of a date was known only by two accessor (or selector) procedures, month-name and date-in-month. 11.3.5 (Brainstorm) Data abstraction examples We provided a bunch of examples of data abstraction. Now it is your turn. Respond with your own example of data abstraction. Can you come up with one that doesn't involve people? 11.4 Homework(2 steps) 11.4.1 (Display page) This week's homework Homework for the upcoming week

Do the following for homework for the next lab.

1. Go back to the last day's discussion and contribute two polite comments that describe improvements to questions your labmates have devised. 2. Contribute to the discussion in the following step. 3. Start on miniproject 1 (see below).

You'll have some time in class next lab to work on on mini-project 1. An important place to start is to begin with a plan. This could be a diagram or pseudo-code. Show your initial plan to your TA before you start coding. If you are in a TuTh section, mini-project 1 will be due at 11:59pm on September 23. Otherwise, if you are in the WF section, it will be due at 11:59pm on September 24. You may work with one other person, who must be in your lab section. Submit your solution as mp1, following the directions for earlier homework submissions. 11.4.2 (Discussion Forum) How can you tell when you've reached a dead end? Inexperienced programmers sometimes have trouble realizing that they're stuck. Having chosen a solution approach that is basically a dead end, they keep working and working on it rather than trying to rethink their approach. Provide some advice for how to recognize that they are stuck. In the next lab, we'll ask you to make two comments on what your classmates have posted. 12 Today's activities 2009-9-17 ~ 2009-9-18 (2 activities) 12.1 Lab activities and homework(2 steps) 12.1.1 (Display page) Lab activities Lab activities

In lab today, your t.a. will review your plan for completing mini-project 1.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 35 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

12.1.2 (Display page) Homework Homework

A solution to mini-project 1 is due Wednesday night for students in TuTh sections and Thursday night for students in WF sections. Submit it as mp1. You have 72 "grace hours" to use for late submissions; don't use them all at once. Reminder: You should submit two files: c.day-span.scm (your solution program) and century-day-span-tests.scm (your tests). There are two more homework activities. First, complete the survey in the accompanying activity. Then, supply two responses to suggestions about recognizing that you are stuck that were contributed last lab:

Why would it be hard to apply someone's suggestion about recognizing stuckness? Does the suggestion work for you? Why or why not? Describe ways of getting unstuck that have worked for you.

Lab activities on Tuesday and Wednesday will involve the topic of recursion. Chapter 11 of Simply Scheme provides appropriate background. 13 Starting to think recursively 2009-9-22 ~ 2009-9-23 (5 activities) 13.1 Reviewing material in chapter 11, and the weekly quiz.(3 steps) 13.1.1 (Display page) What is recursion? The programming techniques you've studied in these first few weeks of CS 3 have only equipped you to write programs that deal with limited amounts of data. For example, you can write a program to add up all of the numbers in a sentence as long as you know in advance how many numbers are in it. You can't write a program that can handle sentences of any length. That's where recursion comes in. With recursion, you don't need to know how to solve the whole problem. All you need to know is

1. when you have solved the problem (e.g. no more numbers in the sentence) 2. how to do one step of the work (e.g. count one number) 3. how to do the rest of the work (e.g. add the rest of the numbers in the sentence) 4. how to combine 2 and 3 (e.g. add that one number to the sum of all the rest)

In other words, do a little bit of work, keep doing work, and stop when you are done. Another example: getting the bottom candy out of a Pez dispenser. Let's say you want to get the last candy out of a Pez dispenser, and you don't care about any of the other candies, if there are some there. If the Pez dispenser is full, you have eleven candies on top of the one you want; but there could only be three candies on top, or seven, or whatever. So, you can't just throw away the first eleven candies exactly -- you need to figure out a way to deal with any number. Here's how you might do it.

How to get the bottom candy out of a Pez dispenser.

1. Look at the first candy, and check to see if it's the last one in the dispenser. If it is, pop it out, keep it, and you are finished. 2. Otherwise, pop out the first candy and throw it away. At this point, you still have a Pez dispenser with candies, so the problem is similar to the one you started with. So, follow the rules on how to get the bottom candy out of the Pez dispenser (i.e., start at step 1).

That's recursion! 13.1.2 (Display page) Here's how Simply Scheme invented downup. Simply Scheme describes how to get a procedure downup from procedures downup1, downup2, downup3, ... (pages 174 to 178). First they defined the downupX procedures directly:

(define (downup1 wd) (se wd)) (define (downup2 wd) (se wd (first wd) wd)) (define (downup3 wd) (se wd (bl wd) (first wd) (bl wd) wd)) (define (downup4 wd) (se wd (bl wd) (bl (bl wd)) (first wd) (bl (bl wd)) (bl wd) wd) )

Then they rearranged them so that each downupn procedure made use of downupn-1:

(define (downup2 wd) (se wd (downup1 (bl wd)) wd)) (define (downup3 wd) (se wd (downup2 (bl wd)) wd)) (define (downup4 wd) (se wd (downup3 (bl wd)) wd))

They noticed that almost all the downupn procedures were essentially the same, and produced the procedure

(define (downup wd) (if (= (count wd) 1) (se wd) (se wd (downup (bl wd)) wd)) ) 13.2 Design individual procedures to make their common pattern more obvious.(4 steps) 13.2.1 (WebScheme) Rewrite reverse procedures to call each other. Define reverse procedures in terms of one another

Consider the problem of returning the reverse of a word, that is, the word whose letters are in order. (For example, the reverse of word is drow. ) Here are some procedures that reverse words of particular lengths.

; Return the reverse of an empty word. (define (reverse0 wd) wd)

; Return the reverse of a 1-character word. (define (reverse1 wd) wd)

; Return the reverse of a 2-character word. (define (reverse2 wd) (word (last wd) (first wd)))

; Return the reverse of a 3-character word. (define (reverse3 wd) (word (last wd) (first (bf wd)) (first wd)) )

; Return the reverse of a 4-character word. (define (reverse4 wd)

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 36 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(word (last wd) (last (bl wd)) (first (bf wd)) (first wd) ) )

; Return the reverse of a 5-character word. (define (reverse5 wd) (word (last wd) (last (bl wd)) (first (bf (bf word))) (first (bf wd)) (first wd)) )

Rewrite reverse3 to call reverse2 , reverse4 to call reverse3 , and reverse5 to call reverse4.

Check answers Correct? (define (reverse3 wd) ) (define (reverse4 wd) ) (define (reverse5 wd) )

13.2.2 (WebScheme) Invent similar copies procedures. Define copies procedures in terms of one another

Consider procedures that return a sentence of a specified number of copies of their word argument:

1. copies0 returns a sentence containing 0 copies of its word argument. Thus (copies0 'hi) should return (). 2. copies1 returns a sentence containing 1 copy of its word argument. (copies1 'hi) should return (hi). 3. copies2 returns a sentence containing 2 copies of its word argument. (copies2 'hi) should return (hi hi). 4. copies3 returns a sentence containing 3 copies of its word argument. (copies3 'hi) should return (hi hi hi). 5. copies4 returns a sentence containing 4 copies of its word argument. (copies4 'hi) should return (hi hi hi hi).

Provide definitions for copies0 through copies4. Design them to call one another as follows:

copies4 should call copies3 ; copies3 should call copies2 ; copies2 should call copies1 ; copies1 should call copies0 .

Remember, fill in all of your answers before clicking ... Check answers Correct? (define (copies0 wd) ) (define (copies1 wd) ) (define (copies2 wd) ) (define (copies3 wd) ) (define (copies4 wd) )

13.2.3 (WebScheme) Invent similar sum-in-interval procedures. Define sum-in-interval procedures in terms of one another

Now let's look at number intervals, which represent pieces of the number line as shown in the diagram below. In Scheme, our number interval will be a two-word sentence whose first word is the left endpoint of the interval and whose second word is the right endpoint. An empty interval is any interval whose left endpoint is greater than its right endpoint.

Consider a procedure sum-in-interval that, given a two-integer sentence representing an interval, returns the sum of all the integers in the interval, including the endpoints. Thus (sum-in-interval '(2 4)) returns 2+3+4, and (sum-in-interval '(4 2)) returns 0 since (4 2) is an empty interval. Again assume you are trying to design a recursive version of sum-in-interval by designing individual sum- in-intervalN as we did for downup and copies . So, sum-in-intervals1 takes an interval that spans a single number, like (1 1) or (5 5) , and sum-in-intervals2 takes an interval that spans two numbers, like (1 2) or (6 7) . Below, complete the definitions for sum-in-interval32 and sum-in-interval33 , that would take intervals that span 32 and 33 numbers respectively. Assume that sum-in-interval31 has already been defined for you. Check answers Correct? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 37 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (sum-in-interval32 intvl) ) (define (sum-in-interval33 intvl) )

13.2.4 (Brainstorm) Choose a good comment for an appearances procedure. Recall the appearances procedure that you experimented with earlier in the course. It takes two arguments, a word and a sentence, and returns the number of times the word occurs in the sentence. Suppose you were trying to design the appearances procedure, and you were trying to define appearances0, appearances1, etc. as in Simply Scheme. Which of the following comments would be most appropriate for the appearances3 procedure? Defend your decision.

1. Return the number of times x occurs in sent, where x appears as the third word in sent. 2. Return the number of times x occurs in sent, where sent contains three words. 3. Return the number of times x occurs in sent, where sent contains three occurrences of x.

13.3 Produce recursive procedures from the individual procedures.(6 steps) 13.3.1 (WebScheme) Design a recursive reverse procedure. Write reverse

Design a recursive version of the reverse procedure that is based on the sequence of procedures reverse0, reverse1, and so on that you just considered. Click on the pointer to run some tests. your procedure run tests result ;; Return the result of reversing the characters in the argument word. (define (reverse wd) (if

) )

reverse call desired result your result (reverse "") "" ???? (reverse 'a) a ???? (reverse 'clint) tnilc ???? If you miss any of these, put an entry in your notebook explaining the reason you missed it.

13.3.2 (WebScheme) Design a recursive copies procedure. Write copies

Design a recursive version of the copies procedure that is based on the sequence of procedures copies0, copies1, and so on that you just considered. Click on the pointer to run some tests. your procedure run tests result ;; Return a sentence that consists of n copies of the given word. ;; n is a nonnegative integer. (define (copies n wd) (if

) )

copies call desired result your result (copies 0 'ha) ( ) ???? (copies 1 'ha) (ha) ???? (copies 5 'ha) (ha ha ha ha ha) ???? If you miss any of these, put an entry in your notebook explaining the reason you missed it.

13.3.3 (WebScheme) Design a recursive appearances procedure. Write appearances

Design a recursive version of the appearances procedure that is based on the sequence of procedures appearances0, appearances1, and so on that you just considered. Click on the pointer to run some tests. your procedure run tests result ;; Return the number of appearances of wd in sent. (define (appearances wd sent)

)

appearances call desired result your result (appearances 'a '(an axe and a saw)) 1 ???? (appearances 'and '( )) 0 ???? ???? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 38 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(appearances 'x '(xyron)) 0 ???? (appearances 'ha '(ha ha ha he said) 3 ???? (appearances 'a '(x o x o)) 0 ???? If you miss any of these, put an entry in your notebook explaining the reason you missed it.

13.3.4 (WebScheme) Design two versions of sum-in-interval. Write two versions of sum-in-interval

Design two different recursive versions of the sum-in-interval procedure that you considered earlier. Your two versions should have different recursive calls. Click on the pointer to run some tests. your procedures run tests result ;; Return the sum of the integers in the given interval, ;; a sentence that contains two integers. ;; The first integer is the starting point of the interval ;; and the second is the ending point. An empty interval, ;; for which 0 should be returned, has its starting point ;; after its ending point (like (5 -1) ). (define (sum-in-interval1 intvl) (if

) ) (define (sum-in-interval2 intvl) (if

) )

argument interval desired result your result from sum-in-interval1 your result from sum-in-interval2 (5 -1) 0 ???? ???? (7 7) 7 ???? ???? (14 17) 62 ???? ???? If you miss any of these, put an entry in your notebook explaining the reason you missed it.

13.3.5 (Display page) Here's a summary of this design method. The activities you just completed illustrate the following way to design a recursive procedure.

1. Our task is to define a procedure that works for arguments of any size. For any particular size, we can produce an answer, so we do that for small-sized arguments:

(define (downup1 wd) ...) ;for words with one letter (define (downup2 wd) ...) ;for words with two letters (define (downup3 wd) ...) ;for words with three letters (define (downup4 wd) ...) ;for words with four letters 2. We notice a pattern in the various individual procedures, and recode them so that they make use of earlier procedures in the sequence. (Principle: don't re-invent the wheel!) For example:

(define (downup4 wd) (se wd (downup3 (bl wd)) wd) ) 3. We recognize the similarity of almost all the individual procedures. (This may require adding a placeholder to increase generality.) Here's an example:

(define (downup wd) (se wd (downup (bl wd)) wd) ) 4. We handle the special case of the procedure that didn't fit the pattern. For example:

(define (downup wd) (if (= (count wd) 1) (se wd) (se wd (downup (bl wd)) wd) ) )

13.3.6 (Display page) Many recursive procedures have the same pattern. What the design method just described produces is a procedure that contains a cond or an if.

The computations that fit the pattern among almost all the individual procedures go together in the cond or if. They are the recursive cases; they all involve one or more calls of the same procedure. The computations that don't fit the pattern are in separate cond or if clauses. They are the base cases.

In a procedure, the recursive calls all involve arguments that are in some sense closer to the base case. This usually means smaller than the argument given to the procedure itself. For example, the recursive call in downup—whose argument is a word named wd—has an argument of (bl wd), a word that has one fewer character. Similarly, reverse, given a word as argument, calls itself with a smaller word as argument; copies calls itself with a smaller number as argument; appearances calls itself with a smaller sentence as argument; and sum-in-interval calls itself with a smaller interval as argument. 13.4 How do I know recursion works?(4 steps) 13.4.1 (Display page) What can help me believe in a recursive procedure? Getting to where you can believe that a recursive procedure is correct sometimes takes time. A good way to do it is to trace through the execution of the procedure, starting with small arguments and working up to larger ones. We'll illustrate this with a procedure that we'll call my-count; it returns the number of words in its sentence argument.

(define (my-count sent) (if (empty? sent) 0 (+ 1 (my-count (butfirst sent))) ) ) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 39 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

1. The smallest possible sentence is the empty sentence. In (my-count '( )), the argument satisfies the first test and thus 0 is returned, as desired.

2. Now we try a sentence with one word, say (clint). The call (my-count '(clint)) results in the following:

(if (empty? '(clint)) 0 (+ 1 (my-count (butfirst '(clint)))) )

The sentence (clint) isn't empty, so the value of (+ 1 (my-count (butfirst '(clint)))) is returned, which is (+ 1 (my-count '( ))). We just determined that (my-count '( )) has value 0, so we add that value to 1 and return the sum 1, as desired.

3. Now let's try a sentence with two words, (mike clint). Tracing the call (my-count '(mike clint)), we get

(if (empty? '(mike clint)) 0 (+ 1 (my-count (butfirst '(mike clint)))) )

This boils down to (+ 1 (my-count (butfirst '(mike clint)))), which is (+ (my-count '(clint))). We just figured out that (my-count '(clint)) was 1, so we substitute that to find that (my-count '(mike clint)) is 2.

Notice that in the example above we started with small arguments and remembered the answers we got from tracing them, so as to be able to substitute those answers in when tracing the procedure on a larger argument. This approach saved a lot of time. 13.4.2 (Display page) We can bypass tracing by believing our comments. A good comment for a procedure provides as much information as possible about its arguments and return value. It allows us to ignore the details of how the procedure works and concentrate on what it does. Good comments are especially useful for understanding recursive procedures. One way to play computer with a recursive procedure is to trace through the recursive call, then through the next recursive call, and so on. With a good comment that matches the code, however, we can imagine in our heads what the recursive call will do without going through all its steps. Consider for example the reverse procedure considered earlier. Here's one Scheme version:

; Return the result of reversing the characters ; of the given word. (define (reverse wd) (if (empty? wd) '( ) (word (last wd) (reverse (butlast wd))) ) )

Let's evaluate (reverse 'abcde) by hand.

abcde isn't the empty word, so we evaluate

(word (last 'abcde) (reverse (butlast 'abcde))) This is the same as

(word 'e (reverse 'abcd))

Here we could keep working through the steps of reverse. An option is to believe the comment, which tells us that (reverse 'abcd) returns dcba. We then evaluate

(word 'e 'dcba)

which gives edcba, the answer we're looking for.

13.4.3 (Brainstorm) What's wrong with this copies procedure? Here's a buggy version of the copies procedure. Test it with the Interpreter. Then report what happened, and describe what the bug is.

(define (copies n wd) (if (= n 0) '() (sentence wd (copies n wd)) ) ) 13.4.4 (Brainstorm) What's wrong with this sum-in-interval procedure? Consider the following version of sum-in-interval.

(define (sum-in-interval intvl) (if (> (first intvl) (last intvl)) 0 (+ (first intvl) (last intvl) (sum-in-interval (se (+ (first intvl) 1) (- (last intvl) 1)) ) ) ) )

Describe what's wrong with it, and give a call to sum-in-interval that demonstrates the bug. 13.5 Homework(3 steps) 13.5.1 (Display page) Homework 1. Read chapters 12 and 13 in Simply Scheme, and the "Difference between Dates, recursive version" case study. 2. Contribute to the discussion in the following step.

13.5.2 (Discussion Forum) Discussion: two real-life examples Post two real-life examples of recursion. Tomorrow, we'll ask you to comment on the examples of two of your classmates, noting their similarities and differences with recursive procedures. 13.5.3 (Display page) Optional: Extra Recursion Practice It is a good idea to try to get as much practice with recursion as possible. You might try programming some of these problems. In the next step you'll brainstorm other problems that can be solved with recursion.

Add up a sentence of numbers Find every odd number in a sentence Find the number of times a word appears in a sentence 14 Working with more complicated recursive procedures 2009-9-24 ~ 2009-9-25 (6 activities) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 40 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

14.1 Use a new tool.(1 step) 14.1.1 (Display page) Try the Replacement Modeler. Now you get to see a neat tool in STk. It's called the Replacement Modeler, and it "slows down", or "steps", the process of evaluation. Here is how to use it.

1. Pick an expression whose evaluation you would like to examine in detail. Type

(model your_expression ) (don't quote the expression). Then press ENTER. A window will appear with your expression in it. 2. Hit RETURN or ENTER to advance through one step of the evaluation. This step will either be to evaluate the arguments of a procedure call, or to substitute argument values into the body of a procedure, or to evaluate part of a cond or an if. The result will appear on the next line of the display.

You can keep hitting RETURN until you reach the final answer or an error. The Modeler can be a really good way to locate bugs in your program. For example, suppose you type

(model (+ 3 (* 4 5) 6 (* 7 (+ 8 9)) 10))

into stk. Another window will pop up with the expression that you gave to the model command. Each time you press RETURN the inner portions of the expression will be evaluated and inserted into the full expression, simplifying it. One RETURN will give

(+ 3 20 6 119 10)

and another RETURN

158

If you want to focus on a particular sub-part of the expression, you can use your mouse to select that sub-part. Hitting RETURN when a sub-part of the expression is highlighted in this way will cause only that highlighted part to be evaluated and substituted. For instance, if you highlight the (* 4 5) in the original expression at the top-line of the replacement modeler window, you will see a second line of

(+ 3 20 6 (* 7 (+ 8 9)) 10)

Note that the (* 7 (+ 8 9)) was not changed. You can use this to focus in more carefully on areas of interest. Be sure to try the replacement modeler with calls to recursive functions. Remember, when you call model, don't quote the argument! Hopefully, this will seem weird to you -- i.e., why isn't the argument evaluated before model sees it? However, you can consider model to be a special form like quote, and the argument will not be evaluated. 14.2 Work with a recursive version of day-span.(4 steps) 14.2.1 (Evidence) Here is code for a recursive version of day-span. If you would like this to open in another window, click here.

; Appendix C ; Recursive computation of the difference between dates

; Return the number of days spanned by earlier-date ; and later-date. ; Earlier-date and later-date both represent dates in 2002, ; with earlier-date being the earlier of the two. (define (day-span earlier-date later-date) (cond ((same-month? earlier-date later-date) (same-month-span earlier-date later-date) ) ((consecutive-months? earlier-date later-date) (consec-months-span earlier-date later-date) ) (else (general-day-span earlier-date later-date) ) ) )

; Access functions for the components of a date. (define (month-name date) (first date)) (define (date-in-month date) (first (butfirst date)))

; Return true if date1 and date2 are dates in the same month, and ; false otherwise. Date1 and date2 both represent dates in 2002. (define (same-month? date1 date2) (equal? (month-name date1) (month-name date2)))

; Return the number of the month with the given name. (define (month-number month-name) (cond ((equal? month-name 'january) 1) ((equal? month-name 'february) 2) ((equal? month-name 'march) 3) ((equal? month-name 'april) 4) ((equal? month-name 'may) 5) ((equal? month-name 'june) 6) ((equal? month-name 'july) 7) ((equal? month-name 'august) 8) ((equal? month-name 'september) 9) ((equal? month-name 'october) 10) ((equal? month-name 'november) 11) ((equal? month-name 'december) 12) ) )

; Return true if date1 is in the month that immediately precedes the ; month date2 is in, and false otherwise. ; Date1 and date2 both represent dates in 2002. (define (consecutive-months? date1 date2) (= (month-number (month-name date2)) (+ 1 (month-number (month-name date1))) ) )

; Return the difference in days between earlier-date and later-date, ; which both represent dates in the same month of 2002. (define (same-month-span earlier-date later-date) (+ 1 (- (date-in-month later-date) (date-in-month earlier-date)) ) )

; Return the number of days in the month named month-name. (define (days-in-month month-name) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 41 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(cond ((equal? month-name 'january) 31) ((equal? month-name 'february) 28) ((equal? month-name 'march) 31) ((equal? month-name 'april) 30) ((equal? month-name 'may) 31) ((equal? month-name 'june) 30) ((equal? month-name 'july) 31) ((equal? month-name 'august) 31) ((equal? month-name 'september) 30) ((equal? month-name 'october) 31) ((equal? month-name 'november) 30) ((equal? month-name 'december) 31) ) )

; Return the number of days remaining in the month of the given date, ; including the current day. Date represents a date in 2002. (define (days-remaining date) (+ 1 (- (days-in-month (month-name date)) (date-in-month date))) )

; Return the difference in days between earlier-date and later-date, ; which represent dates in consecutive months of 2002. (define (consec-months-span earlier-date later-date) (+ (days-remaining earlier-date) (date-in-month later-date)) )

; Return the name of the month with the given number. ; 1 means January, 2 means February, and so on. (define (name-of month-number) (item month-number '(january february march april may june july august september october november december) ) )

; Return the sum of days in the months represented by the range ; first-month through last-month. ; First-month and last-month are integers; 1 represents January, ; 2 February, and so on. ; This procedure uses recursion. (define (day-sum first-month last-month) (if (> first-month last-month) 0 (+ (days-in-month (name-of first-month)) (day-sum (+ first-month 1) last-month)) ) )

; Return the number of the month that immediately precedes the month ; of the given date. 1 represents January, 2 February, and so on. (define (prev-month-number date) (- (month-number (month-name date)) 1) )

; Return the number of the month that immediately follows the month ; of the given date. 1 represents January, 2 February, and so on. (define (next-month-number date) (+ (month-number (month-name date)) 1) )

; Return the difference in days between earlier-date and later-date, ; which represent dates neither in the same month nor in consecutive months. (define (general-day-span earlier-date later-date) (+ (days-remaining earlier-date) (day-sum (next-month-number earlier-date) (prev-month-number later-date) ) (date-in-month later-date) ) ) 14.2.2 (Brainstorm) Find a bug. Your helper monkey accidentally changes a single symbol in one of the lines of the recursive day- span program, with the result that day-span's return values are now too large: call to day-span returned value (day-span '(january 1) '(december 31)) 396 (day-span '(february 1) '(december 31)) 362 (day-span '(january 1) '(november 30)) 365 What symbol could your partner have changed to produce this behavior? 14.2.3 (Brainstorm) How did you find it? What technique did you use to find the bug? Did you guess wildly? Did you reason it out? Give us some details. 14.2.4 (Brainstorm) Can day-span be simplified? Are the first two cases in day-span still necessary? That is, can day-span now be coded merely as a call to general-day-span? Explain why or why not. 14.3 Design some more recursive procedures.(2 steps) 14.3.1 (WebScheme) Write down-to-0. Write down-to-0

Write a procedure named down-to-0 that, given an integer n as argument, returns the sentence (n n-1 ... 0) (Do this without using reverse. ) If n is negative, down-to-0 should return the empty sentence. your procedure run tests result ;; Return a sentence that, given an integer n, ;; contains the integers from n down to 0: (n n-1 ... 0) (define (down-to-0 n) (if

) )

down-to-0 call desired result your result (down-to-0 -3) ( ) ???? (down-to-0 0) (0) ???? (down-to-0 3) (3 2 1 0) ???? If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 42 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

14.3.2 (WebScheme) Write the remove procedure. Write remove

Write a procedure named remove that, given a character char and a word wd as arguments, returns the result of removing all occurrences of char from wd. your procedure run tests result ;; Return the result of removing all occurrences of the given character ;; from the given word. (define (remove char wd)

)

remove call desired result your result (remove 'a 'radar) rdr ???? (remove 'a 'xyz) xyz ???? (remove 'a 'aaaa) "" ???? (remove 'a 'pear) per ???? If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

14.4 Design a recursion using simple cases and clones.(4 steps) 14.4.1 (Display page) Here's another way to approach the design of recursive procedures. So far, we have seen how to design recursive procedures by doing the following:

1. designing a procedure to handle an argument of size 0, another procedure to handle an argument of size 1, a third to handle an argument of size 2, and so on; 2. rewriting those procedures if necessary to maximize their similarity; 3. designing one or more recursive calls that match the pattern of the rewritten procedures; 4. fixing up the base case(s) to work correctly with the recursive calls we've just designed.

Many programmers prefer to work in the opposite sequence. They look for all the cases that are easy to solve—for example, those involving small numbers or small sentences or words—and use these as their base cases. For the copies procedure you saw earlier, they might start coding with three easy cases:

; Return a sentence that contains n copies of the word x. (define (copies n x) (cond ((= n 0) '( )) ((= n 1) (sentence x)) ((= n 2) (sentence x x)) ; the remainder of the procedure is yet to fill in. )) Then they consider a big argument, and say, "Suppose I had a clone—a copy of myself—that would give me a sentence of any number of copies of my x, except that the number of copies it would give me has to be smaller than my n. How would I use the clone's answer to produce my own answer?" They would continue by asking the clone for n-1 copies of x; then they would add one more copy and return the result. 14.4.2 (Brainstorm) Try out this approach. We will now try to apply this use-a-clone approach to the problem of writing a procedure sent-max that returns the largest value in its argument, a nonempty sentence of numbers. Suppose you are sent-max, and someone gives you a sentence that contains five numbers. You want to prepare an argument to give your clone; he or she will return to you the maximum value in whatever sentence you provide, as long as it's a simpler sentence than the one you were given. Which of the following simpler sentences should you give your clone?

1. butfirst of the sentence you were given (its last four numbers); 2. some other sentence that contains four numbers; 3. a sentence with five numbers that results from subtracting 1 from each of the numbers in your sentence (e.g. if the sentence you were given was (3 -2 7 -4 5), you would give the clone the sentence (2 -3 6 -5 4).

Explain your answer by saying how you would use the result that the clone returns to you. 14.4.3 (WebScheme) Write a recursive predicate. Write two versions of all-odd?

Design two different recursive versions of a procedure named all-odd? that, given a nonempty sentence of numbers, returns true if all the numbers in the sentence are odd and returns false otherwise. The first of your two versions should use if or cond without using and or or ; the other should do just the opposite. Click on the pointer to run some tests. your procedures run tests result ;; Return true if all the numbers in the given sentence are odd. ;; Return false otherwise. ;; The argument sentence contains at least one number. ;; Do not use 'and' or 'or' in this solution. ;; all-odd-1 is the first version: (define (all-odd-1? sent)

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 43 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

) ;; all-odd-2 is the second version: ;; Do not use 'if' or 'cond' in this solution. (define (all-odd-2? sent)

)

argument interval desired result your result from all-odd-1? your result from all-odd-2? (2 4 -16) #f ???? ???? (5 -3 17) #t ???? ???? (5) #t ???? ???? (5 -43 20) #f ???? ???? If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

14.4.4 (Brainstorm) What should all-odd? return for an empty argument? It's not always clear what a recursive procedure should return for an argument like the empty sentence or word. Suppose your version of all-odd? had to deal with the possibility of an empty argument. What should (all-odd? '( )) return, and why? (If you are among the first to do this problem, be sure to return later to check the answers of your classmates.) 14.5 Design recursions that examine more than one word in a sentence at a time.(6 steps) 14.5.1 (Display page) Consider -pairs example from the book. Simply Scheme describes the procedure letter-pairs; given a word, letter-pairs returns a sentence that contains all pairs of consecutive letters in the word. For example, (letter-pairs 'george) returns (ge eo or rg ge). Here's their code.

(define (letter-pairs wd) (if (<= (count wd) 1) '( ) (sentence (first-two wd) (letter-pairs (butfirst wd)) ) ) )

; Helper procedure: ; Return a sentence that contains the first two letters ; of the given word (which must contain at least two words). (define (first-two wd) (word (first wd) (first (butfirst wd))) ) The interesting thing about this example is not the recursive call, in which the argument is (butfirst wd) as in many of the other examples. It's the base case, which tests for a word with 0 or 1 character rather than just an empty word. The reason for this base case is to protect the call to first-two, which is going to use the second character in its argument word. If the procedure were coded as

(define (letter-pairs wd) (if (empty? wd) '( ) (sentence (first-two wd) (letter-pairs (butfirst wd)) ) ) )

a crash in first-two would result. 14.5.2 (Display page) Work with procedures that remove duplicate words from a sentence. The next few steps involve procedures that return the result of removing duplicate words from their sentence arguments. 14.5.3 (Display page) Write dupls-removed. Write a procedure named dupls-removed that, given a sentence as argument, returns the result of removing duplicate words from the sentence. (The member? procedure will be useful.) Put the procedure into a file named dupls-removed.scm. Test your procedure on the following examples:

expression value to return (dupls-removed '(a b c)) (a b c) (dupls-removed '(a b c a d e b)) (c a d e b) 14.5.4 (Brainstorm) Analyze dupls-removed. Suppose that your dupls-removed procedure (assuming it works correctly) were given a sentence containing a single A, two B's, and a single C, and it returned the sentence (A B C). What are all possibilities for the argument sentence that would produce this result? Briefly explain your answer. 14.5.5 (Brainstorm) Analyze, then fix a buggy adj-dupls-removed procedure Consider the procedure adj-dupls-removed given below. Given a sentence as argument, it is supposed to return the result of removing all but the last of any sequence of duplicate adjacent elements. For example,

(adj-dupls-removed '(A B B C D D D E))

should return (A B C D E).

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 44 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (adj-dupls-removed sent) (cond ((empty? sent) '( )) ((equal? (first sent) (first (butfirst sent))) (adj-dupls-removed (butfirst (butfirst sent))) ) ((empty? (butfirst sent)) sent) (else (se (first sent) (adj-dupls-removed (bf sent)) ) ) ) ) Describe, as completely as possible, the set of arguments for which it does not perform as specified. Then fix adj-dupls-removed. 14.5.6 (Display page) Design is-sorted?. Write and test a procedure named is-sorted? that, given a sentence of numbers, returns true if they are sorted and false otherwise. A sentence is sorted when its first word is less than or equal to its second, which is less than or equal to its third, and so on. An empty sentence is also sorted. Put your procedure into a file named utils.scm. You will occasionally be using utils.scm in later homework problems—for instance, where you need to know whether a sentence is sorted for some sub-part of the problem. You will submit utils.scm for this session's homework as well. 14.6 Homework(1 step) 14.6.1 (Display page) Do the following for homework. Homework 8

1. Go back to the last homework and make two thoughtful comments on other people's posts.

2. Complete the files dupls-removed.scm and utils.scm (which will contain the procedures dupls-removed and is-sorted? respectively). Place these files in the hwk8 directory and submit them as hwk8 in the usual way. You don't need to submit test cases, but be sure to give a good comment at the top of each procedure!

3. Read the "Roman Numerals" case study.

15 Continuing with more complex recursive procedures 2009-9-29 ~ 2009-9-30 (3 activities) 15.1 Here's more information about the Modeler.(1 step) 15.1.1 (Display page) Here are three more commands you can use with the Modeler. In the Replacement Modeler (which you access by starting stk command to your xterm window), there are three other things you can type along with RETURN.

You can click on a procedure call in the last expression on the display window. Hitting RETURN will then take one step in the evaluation only of that expression. You can hit ENTER, which carries out the evaluation of the selected expression all the way (as if you had typed it into stk). You can hit DELETE, which erases the last expression in the display window.

15.2 Work with the "Roman Numerals" case study programs.(3 steps) 15.2.1 (Display page) Add some new Roman digits. Modify the version of the program in Appendix A to handle two new Roman digits: T, meaning 10000, and F, meaning 5000. M can prefix T to represent 9000 or F to represent 4000. No more than three occurrences of T may appear consecutively, and no more than one occurrence of F may appear at all. (You may assume that the argument provided to your revised decimal-value procedure will satisfy these requirements.) Put the procedures that change, along with your test expressions for the modified program, into a file named TFchanges.scm. 15.2.2 (Display page) Design test cases to detect a bug. First, find a partner. Have him or her create a version of the program in Appendix A in which one of the bf calls in the prefix-values-removed procedure has been replaced by bf (bf ..., thus making two calls to bf where there had been only one before. Then, you are to produce a set of test calls to prefix-values-removed. If your tests expose your partner's change, you get a point. Otherwise, he or she gets the point. Your instructor and lab assistants will be keeping score. 15.2.3 (Display page) Reorganize the program. Write and test a procedure named grouped that, given a Roman numeral as argument, returns the result of translating each prefix and prefixed digit pair into a two-character word. For example, (grouped 'MMMXCIV) should return (M M M XC IV). Then modify the program in Appendix B to make good use of the grouped procedure. Put your solution and test expressions into a file named roman+grouped.scm. 15.3 Homework(2 steps) 15.3.1 (Display page) Details Contribute a post to the following discussion on important things to learn from the "Roman Numerals" case study. Next lab, we'll ask you to make two comments on this discussion. 15.3.2 (Discussion Forum) What are the three most important things to learn from the case study? List the three most important things to learn from the "Roman Numerals" case study? 16 Working with recursions that require multiple arguments 2009-10-01 ~ 2009-10-02 (3 activities) 16.1 Design recursive procedures with two arguments.(6 steps) 16.1.1 (Display page) See how my-equal? is coded. We now move on to more general recursions, starting with a version of Scheme's builtin equal? procedure. (We'll be doing this using the builtin equal? only to compare sentences, not words). We list a bunch of cases for which it's easy to see the answer.

two empty sentences are equal; an empty sentence is not equal to a nonempty sentence; more generally, two sentences of unequal lengths are not equal; a one-word sentence is equal to another one-word sentence that contains the same word; a one-word sentence is not equal to another one-word sentence that contains a different word.

This should do for now. It gives us the following framework.

(define (my-equal? sent1 sent2) (cond ((and (empty? sent1) (empty? sent2)) #t) ((or (empty? sent1) (empty? sent2)) #f) ; Make sure you understand why the previous clause worked! http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 45 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

((not (= (count sent1) (count sent2))) #f) ((and (= (count sent1) 1) (equal? (first sent1) (first sent2))) #t) ((and (= (count sent1) 1) (not (equal? (first sent1) (first sent2)))) #f) ... ) ) Now we picture two big sentences of equal length, and imagine how a clone that works with smaller sentences can be of use. It might help to pretend we can only see a little bit of each sentence, say, only the first words. Two more cases appear. If the first word in sent1 isn't the same as the first word in sent2, we can return false. If the two first words are equal, however, the clone can help us.

We ask the clone whether (butfirst sent1) is equal to (butfirst sent2). If the clone says no, we return false; there must be a mismatch somewhere down the line. If the clone says yes, we return true, since we know the firsts of the two sentences match. This gives us the following procedure:

(define (my-equal? sent1 sent2) (cond ; all the base cases we invented above go here ((not (equal? (first sent1) (first sent2))) #f) (else ; use the clone (my-equal? (butfirst sent1) (butfirst sent2)) ) ) )

Why didn't we ask the clone whether sent1 was equal to (butfirst sent2) or vice-versa? That's not helpful information. In fact, we already know the answer; since we made sure that sent1 and sent2 were equally long, sent1 and (butfirst sent2) must contain different numbers of words and thus aren't equal.

16.1.2 (Brainstorm) Clean up the base cases. The my-equal? procedure we just designed had more base cases than necessary. Give the bare minimum of base cases that the my-equal? procedure needs, together with a short explanation of why the others aren't needed. Here was the code.

(define (my-equal? sent1 sent2) (cond ((and (empty? sent1) (empty? sent2)) #t) ((or (empty? sent1) (empty? sent2)) #f) ((not (= (count sent1) (count sent2))) #f) ((and (= (count sent1) 1) (equal? (first sent1) (first sent2))) #t) ((and (= (count sent1) 1) (not (equal? (first sent1) (first sent2)))) #f) ((not (equal? (first sent1) (first sent2))) #f) (else ; use the clone (my-equal? (butfirst sent1) (butfirst sent2)) ) ) ) 16.1.3 (Display page) Try "zipping" two sentences. Write and test a procedure named zip that "zips" two sentences of equal lengths like a zipper. In the result returned by zip, the first word should be the first word from the first sentence and the second word should be the first word from the second sentence. Then comes the second word from the first sentence and the second word from the second sentence, and so on. To shorten a long story with an example, (zip '(1 2 3 4) '(A B C D)) should return

(1 A 2 B 3 C 4 D)

Put your solution into a file named zip.scm. 16.1.4 (Display page) Try merging two sentences. The procedure named combined-in-order whose framework appears below is a somewhat more difficult variation of the "two-sentences" recursion. Combined-in-order takes two sorted sentences of numbers as arguments; that is, in each argument sentence, the first number is less than or equal to the second, which is less than or equal to the third, and so on. Combined-in-order combines the sentences to form another sentence containing all the numbers in the argument sentences in sorted order. Here are some examples.

expression desired result (combined-in-order '(1 3 7) '(1 2 3 4)) (1 1 2 3 3 4 7) (combined-in-order '(1 3 7) '(4)) (1 3 4 7) (combined-in-order '(1 3 3) '(1 3 7)) (1 1 3 3 3 7) (combined-in-order '(1 3 7) '( )) (1 3 7)

Fill in the framework. Then devise a thorough set of test calls that exercise every part of the cond. Keep track of your bugs and the reasons for them in your notebook. Finally, put your completed combined-in-order procedure together with your test calls into a file named combined-in- order.scm.

; Framework for combined-in-order (define (combined-in-order sent1 sent2) (cond ((empty? sent1) _____ ) ((empty? sent2) _____ ) ((< (first sent1) (first sent2)) _____ ) ((> (first sent1) (first sent2)) _____ )

(else ; firsts are equal _____ ) ) ) 16.1.5 (Display page) Design my-item. The item procedure, given a number pos and a sentence sent, returns the word at position pos in sent (positions start at 1). Write and test my-item, a recursive version of the builtin item. Put your solution in a file named my-item.scm. Again, keep track of your bugs in your notebook. Here's a start at the code.

(define (my-item pos sent) ... ) 16.1.6 (Brainstorm) Consider some buggy my-item procedures. Consider the following two buggy versions of my-item. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 46 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (my-item1 pos sent) (define (my-item2 pos sent) (if (= pos 1) (if (= pos 1) (first sent) (first sent) (my-item1 (- pos 1) sent) ) ) (my-item2 pos (bf sent)) ) )

Without using a Scheme interpreter, determine what each version does. Also indicate if you encountered one of these bugs in your own version of my-item. (Don't worry, your name won't appear on your answer.)

16.2 Try some accumulating recursions.(3 steps) 16.2.1 (Display page) Here's the pattern for accumulating recursions. Earlier you wrote a sum-in-interval procedure that probably looked as follows:

(define (sum-in-interval intvl) (if (> (first intvl) (last intvl)) 0 ; empty interval (+ ; nonempty interval (first intvl) (sum-in-interval ; call with shorter interval (sentence (+ 1 (first intvl)) (last intvl)) ) ) ) ) Another way to write this uses a helper procedure with an extra argument.

(define (sum-in-interval intvl) (sum-helper intvl 0) )

; Return the sum of the integers in intvl plus sum-so-far, ; the sum accumulated in earlier calls to sum-helper. (define (sum-helper intvl sum-so-far) (if (> (first intvl) (last intvl)) sum-so-far (sum-helper (sentence (+ 1 (first intvl)) (last intvl)) (+ sum-so-far (first intvl)) ) ) )

Each recursive call accumulates more information in its sum-so-far argument. Thus, recursions of this form are called accumulating recursions. 16.2.2 (Display page) Write sent-max with an accumulating recursion. Fill in the blanks in the following implementation of sent-max. Don't change any of the existing code.

; Return the largest value in the given sentence. ; sent is nonempty and contains only numbers. (define (sent-max sent) (sent-max-helper (bf sent) _____ ) )

(define (sent-max-helper sent max-so-far) (if (empty? sent) max-so-far (sent-max-helper (bf sent) _____ ) ) )

You might want to use the max procedure here. max takes some numbers and returns the biggest number. For example, (max 2 3 5) returns 5. Test the procedure, and put it and your tests in a file named sent-max2.scm. 16.2.3 (Display page) Reorganize roman-sum. Write and test a procedure named roman-sum-helper that is called by a modified roman-sum as follows:

(define (roman-sum number-sent) (if (empty? number-sent) 0 (roman-sum-helper (first number-sent) (bf number-sent) (first number-sent)) ) )

Roman-sum-helper takes three arguments:

(define (roman-sum-helper so-far number-list most-recent) ...

Thus the following recursive calls should result from evaluating the expression (roman-sum '(100 10 50 1 5)):

(roman-sum-helper 100 '(10 50 1 5) 100) (roman-sum-helper 110 '(50 1 5) 10) (roman-sum-helper 140 '(1 5) 50) (roman-sum-helper 141 '(5) 1) (roman-sum-helper 144 '( ) 5)

You will need to pay particular attention to how the so-far argument gets updated when a prefix is present. 16.3 Homework(3 steps) 16.3.1 (Display page) Details. Go back to the last homework and make two thoughtful responses on other people's posts. Then, contribute a post to the following discussion on how to reorganize the "Roman Numerals" case study. Next lab, we'll ask you to make two comments on this discussion. You should also start the compressed homework. It will be due a week from now 16.3.2 (Discussion Forum) Change digit-values or sum-of-all? Why or why not? Complicating existing code, or writing new code?

In the case study, we chose not to change digit-values and sum-of-all. Would you have done that? Why or why not? 16.3.3 (Evidence) Compress a sentence. Background

Data stored on computers can often be compressed to take less space. The compression process detects patterns in the data, and codes those patterns more compactly. (People who have trouble throwing things away find this very handy.) Picture data is especially appropriate for compression. Conceptually. a black-and-white picture is just a grid of black and white "dots". It can be represented by a sequence of 0's and 1's, with a 0 representing each white dot and a 1 representing each black

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 47 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

dot. Pictures often contain large regions of a single color, however, and such a region can also be represented just a few values: a number representing the color, and one or two numbers saying how much of that color there is in the region. This technique can also be applied to sentences of 0's and 1's. A sequence of consecutive identical numbers in the sentence can be replaced by two values: the number of words in the sequence, and a single copy of the repeated number. Here's an example: uncompressed sentence compressed sentence (0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 1) (4 0 1 4 0 9 1)

Problem

Write a procedure named compressed that implements the process just described. You may assume that the argument to compressed is a sentence containing only 0's and 1's. The argument may be empty. The sentence returned by compressed will have several properties.

Its words (if any) are all nonnegative integers. Every occurrence of an integer greater than 1 is immediately followed in the sentence by a 0 or a 1. For example, compressed should never return the sentence (2 1 2) or (3 2 1). Consecutive 0's or 1's will not occur. A sequence of, say, five consecutive 0's would have been replaced by the values 5 and 0, and a sequence of two consecutive 1's would have been replaced by the values 2 and 1. Consecutive groups of 0's or 1's will not occur. For example, the sequence (4 1 5 1) represents a sequence of nine 1's that would have been compressed to (9 1).

Your procedure should only compress sentences that need compressing; for example, (compressed '(0 1 0 1)) should return (0 1 0 1). The compressed version of any sentence of 0's and 1's should be no longer than the sentence itself. Your procedure may call helper procedures; test these by themselves as well as in combination. If your program requires more than a half-page of code, however, you should rethink your solution. Include a comment with each of your procedures that describes its arguments and return values as specifically as possible. At least one of your procedures will be recursive. Avoid unnecessarily long or complex case analysis. Use reasonable names for procedures and place holders. Test compressed on at least one sentence in each of the following categories: a sentence ending with a group a sentence starting with a group of 1's of 1's a sentence ending with a group a sentence starting with a group of 0's of 0's a sentence starting with 1 0 a sentence ending with 1 0 a sentence starting with 0 1 a sentence ending with 0 1 a sentence containing consecutive compressible an empty sentence groups When finished, you will submit a file named compress.scm. Keep this in a directory named hwk10, where you will submit it. 17 Miniproject 2: Number-name 2009-10-01 ~ 2009-10-09 (1 activity) 17.1 Write a program to spell out numbers.(3 steps) 17.1.1 (Display page) Here are the project details. Spelling numbers

Write and test a procedure named number-name that takes a non-negative integer argument and returns a sentence containing that number spelled out in words. (This assignment is on page 233 of Simply Scheme; more details appear there.) Note, however, that you will be required to handle any non-negative integer up to 999 decillion; that is, all integers between 0 and 999 decillion, inclusive. You may find the following sentence helpful: '(thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion) You will need helper procedures; test them in isolation as well as with number-name. Include a comment with each of your procedures that describes its arguments and return values as specifically as possible. We encourage you to reuse any procedures you or we have written so far during the course. Avoid unnecessarily long or complex case analysis; use item or member? to avoid long cond expressions. Use reasonable names for procedures and place holders. Submission instructions are detailed in a following activity.

Testing details

You will be using a new testing library in this project, and you will create a separate file containing your tests. Detailed instructions are in a following activity.

Working in a partnership

You are encouraged to work in a partnership of two on this project. There are benefits to working in a group, certainly, but don't expect that there won't also be extra time that you need to devote to building consensus, etc. You and your partner need supply only one solution: that is, only one student needs to submit the project. However, put both your names and instructional logins in a comment at the top of number-name.scm. Also include a document named number-name.README that also includes your names and describes how each partner contributed to the project.

Scheme and leading zeroes in numbers

An aspect of Scheme that's troublesome for this problem is its handling of words that are also numbers. When you type an expression to the Scheme prompt that contains a number, Scheme removes the number's leading zeroes. Here are examples.

STk> 007 7 STk> '(007 008) (7 8) To retain the leading zeroes, you have to enclose the number in double quotes: http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 48 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

STk> "007" "007" STk> '("007" 008) ("007" 8) Scheme also removes leading zeroes from the result of an arithmetic operation.

STk> (+ "007" "008") 15 17.1.2 (Display page) Using the cs3 testing library for number-name. Testing number-name

For this project, you will be using some simple procedures to help you more easily create and manage your tests. Your tests will consist of a set of test cases, where each test case contains:

a Scheme expression -- this is a call to the procedure that you want to test, with arguments that will check a specific aspect of its functionality. an expected return value -- this is what the Scheme expression should return if it is operating correctly. a name -- so you can identify the particular test case when it is listed in a report.

You are expected to create test cases for the number-name procedure as well as its helper procedures.

Using the testing framework:

You will be using a new testing framework to test your number-name code. There are three functions you need to know:

(add-test-case test-name expected-return-value Scheme-expression) (run-test-cases) (clear-test-cases)

add-test-case

add-test-case takes in a quoted name, the return value you expect to get when evaluating the testing expression, and the Scheme expression itself. Each test case you add needs to have a unique name; add-test-case will warn you if the name is not unique. The first argument must be quoted -- it is simply a name. The second argument may or may not be quoted: if you want to give a specific word or sentence as an expected value, you need to quote this. If you want evaluate some expression to give the expected value, then it shouldn't be quoted. The third argument should never be quoted in practice -- this is the Scheme expression that you want evaluated. Remember, quote things that are names or specific words/sentences; don't quote things that need to be evaluated. STk> (add-test-case 'single-digit-test '(nine) (number- name 9)) okay STk> (add-test-case 'hundreds-test '(one hundred) (number-name 100)) okay run-test-cases run-test-cases will run all the test cases you added using add-test-cases. STk> (run-test-cases) (----- Running 3 tests... Failure output below. -----) (----- Done. 0 failed test(s). 0 error(s). -----) okay If your test cases contain cases that generate errors or return values other than the expected value, they will be listed in the report: STk> (run-test-cases) (----- Running 3 tests... Failure output below. -----) nine ERROR: on show-hundreds (----- Done. 1 failed test(s). 1 error(s). -----) okay In the above report, the test case named nine didn't return its expected value, and the test case named show-hundreds generated an error when it was run (and, therefore didn't return any value!). clear-test-cases clear-test-cases erases all the test cases that you have currently added. STk> (clear-test-cases) okay

Setting up and running your tests You will create the file number-name-tests.scm to hold all of the test cases that you generate for this project. (Note, this is a different style than was discussed earlier, where tests were included directly after the definition of a procedure.) Put a comment at the top of your testing file describing it, and immediately after include the expression (clear-test-cases). This ensures that, every time the file is loaded, you start with an empty set of test cases. Next, include groups of test cases for each procedure that you want to test. Put a comment at the top of the group stating what procedure it is for and anything special you need to remember. Below the comment, add your test cases with appropriate calls to add-test-case. For example, a testing file might look like:

;;number-name-tests.scm http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 49 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(clear-test-cases) ;;MAKE SURE THIS IS INCLUDED AT THE TOP OF YOUR FILE

;;number-name: testing one-digit-numbers (add-test-case 'one '(one) (number-name 1)) (add-test-case 'five '(five) (number-name 5)) (add-test-case 'nine '(nine) (number-name 9))

;;number-name: testing two-digit-numbers (add-test-case 'thirteen '(thirteen) (number-name 13)) (add-test-case 'twenties '(twenty one) (number-name 21)) Once you have written your test file, send all the definitions to STk by using the Send Buffer command in emacs. Finally, you can use (run-test-cases) from within STk to test your program. As you make changes to the code, use (run-test- cases) to check that you haven't broken anything that used to work! If you add more test cases, simply reload the Emacs buffer containing your test cases. 17.1.3 (Display page) Due date and submission instructions A solution to this project is to be submitted by Monday, October 12 at 11:59pm for TuTh labs and by Tuesday, October 13 at 11:59pm for WF labs. Make a directory named mp2, and within it store your code in the file number-name.scm and your tests in the file number-name-tests.scm. If you worked in a partnership, be sure to include your names and instructional logins in a comment at the beginning of number-name.scm. And, also include the file number-name.README, in which you say how each person contributed to the final code. Submit your files in the standard way: via the Unix command submit mp2 from within the mp2 directory. If you worked in a partnership, only one person should to submit the code. Remember—40 is spelled "forty"! Please don't use "and" to separate your words. 102 should be (one hundred two), not (one hundred and two). 18 Advanced recursions 2009-10-06 ~ 2009-10-07 (6 activities) 18.2 Recursions fall into patterns.(3 steps) 18.2.1 (Display page) What are patterns? Compare the following two procedures (assuming square is defined):

(define (all-squared sent) (if (empty? sent) '() (se (square (first sent)) (all-squared (bf sent)))))

(define (all-count sent) (if (empty? sent) '() (se (count (first sent)) (all-count (bf sent)))))

The only differences between the two are the use of square or count. Recursion problems tend to fall into certain patterns. If you solve a hundred problems, you have probably written less than twenty really unique procedures. If you can see that a new problem is pretty much the same as one you've already done, you can save a lot of time. We'll show you some of the classic patterns today. 18.2.2 (Display page) Here are the patterns. Here are some of the recursive patterns. Variable parts of the pattern, which will change from procedure to procedure, are listed in italics.

Application-to-all

(sometimes called mapping) This pattern fits recursions that take a sentence as argument and return the result of doing something to every element in the sentence. Examples are the all-count and all-squared procedures just mentioned. The pattern is

(define (proc-applied-to-all sent) (if (empty? sent) '() (se (proc (first sent)) (proc-applied-to-all (bf sent))))) A similar pattern applies to words instead of sentences. This pattern has several names. Someone with a mathematical background would call it "mapping". It may also be viewed as translation, as for instance in the digit-values procedure from the "Roman Numerals" case study.

Finding

Here, you have a sentence or word and you want to determine whether it contains an "interesting" word or character. The member? procedure is an example, as is the part of the Pig Latin procedure from Simply Scheme that looks for a vowel. The pattern is

(define (found? sent-or-word) (cond ((empty? sent-or-word) #f) ((interesting? (first sent-or-word)) #t) (else (found? (butfirst sent-or-word))) ) )

Counting

Given a sentence or word, you want to know how many of its component words or characters are interesting. The count procedure is a straightforward example; the appearances procedure is another. Here's the pattern:

(define (count sent-or-word) (cond ((empty? sent-or-word) 0) ((interesting? (first sent-or-word)) (+ 1 (count (butfirst sent-or-word))) ) (else (count (butfirst sent-or-word))) ) )

Filtering

What you want to do is discard all the uninteresting words in a sentence or characters in a word. Examples from lab are the remove and dupls-removed procedures. The pattern is similar to that of Finding and Counting: http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 50 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (filtered sent) (cond ((empty? sent) '()) ((interesting? (first sent)) (sentence (first sent) (filtered (butfirst sent))) ) (else (filtered (butfirst sent))) ) ) There is a similar pattern for words. Some people talk about "keeping" rather than "filtering". (These are probably the same people that think a glass is half full rather than half empty.)

Testing-all

Here, the task is to see whether all the words in a sentence or characters in a word are interesting. The all-odd? procedure from lab is an example. The pattern is

(define (all-are-interesting? sent-or-word) (cond ((empty? sent-or-word) #t) ((interesting? (first sent-or-word)) (all-are-interesting? (butfirst sent-or-word)) ) (else #f) ) )

Combining

Examples of this pattern return the result of some sort of combination of words in a sentence or characters in a word. Counting is an example of combining; some more straightforward examples are finding the largest or smallest word in a sentence. The day-sum procedure in the code for part 2 of the "Difference Between Dates" case study and the sum-of-all procedure from the "Roman Numerals" case study are other examples. Here's the pattern.

(define (combination sent-or-word) (if (empty? sent-or-word) the-empty-combination (combined (first sent-or-word) (combination (butfirst sent-or-word)) ) ) )

Here's how to write the sent-min procedure an example of this pattern. Note the correspondence between the parts. Note also that pattern instances occasionally need to be "tweaked" to handle certain special cases—here, the inability to return the smallest number in an empty sentence.

(define (sent-min sent) (if (empty? (bf sent)) (first sent) (min (first sent) (sent-min (bf sent))))) 18.2.3 (Brainstorm) Invent another pattern. Not all the procedures we've seen thus far fall into the patterns we've just seen. Invent another pattern that covers at least two recursive procedures you've seen other than those already identified. Also describe the procedures that are instances of your pattern. 18.3 Work with some "advanced" recursions.(1 step) 18.3.1 (Display page) What is "advanced" recursion? The recursion you have done up till now may have seen pretty complicated, but most of it is still essentially linear. That is, it only involves doing one thing at a time. For example,

(define (remove me fromthis) (cond ((empty? fromthis) '()) ((equal? me (first fromthis)) (remove me (bf fromthis))) (else (se (first fromthis) (remove me (bf fromthis))))))

remove only goes through the sentence one word at a time. Recursion is "advanced" when it does more than one thing at once. For example, check out these two procedures.

;; Return the result of removing all of the vowels ;; from all of the words in the sentence in-this. (define (no-vowels in-this) (if (empty? in-this) '() (se (no-vowels-in-word (first in-this)) (no-vowels (bf in-this)) ) ) )

;; Return the result of removing all of the vowels ;; from the given word. (define (no-vowels-in-word wd) (cond ((empty? wd) "") ((member? (first wd) 'aeiou) (no-vowels-in-word (bf wd))) (else (word (first wd) (no-vowels-in-word (bf wd))))))

No-vowels just seems to go through a sentence and no-vowels-in-word just goes through a word, but together they go through every letter of every word in a sentence. This is advanced. This isn't the only kind of advanced recursion out there. As long as there are several things going on at once, you have advanced recursion. You will have plenty of chances to try out different kinds of advanced recursion today. 18.4 Do some sorting.(7 steps) 18.4.1 (Display page) First write insert. Write and test a procedure named insert that takes two arguments. The first is a number. The second is a sentence of numbers, sorted so that the first number is less than or equal to the second, which is less than or equal to the third, and so on. (The sentence may be empty.) Insert should return the result of inserting the number into the sentence in its proper position. Here are examples.

expression intended result (insert 5 '( )) (5) (insert 5 '(1)) (1 5) (insert 5 '(6)) (5 6) (insert 5 '(1 5 6)) (1 5 5 6) (insert 5 '(3 3 3)) (3 3 3 5) (insert 5 '(6 7 20)) (5 6 7 20)

Put your solution and your test expressions into a file named insertion-sort.scm.(In the next step http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 51 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

you'll add another procedure to this file.) 18.4.2 (Display page) Now write sorted. Now write and test a procedure named sorted. Given a possibly unsorted (and possibly empty) sentence of numbers, it should return a sorted sentence that contains the same numbers. Your sorted procedure must use the insert procedure you just wrote. Examples:

expression desired result (sorted '( )) ( ) (sorted '(15)) (15) (sorted '(20 10) (10 20) (sorted '(1 2 34)) (1 2 34) (sorted '(2 34 1)) (1 2 34) (sorted '(9 8 8 3)) (3 8 8 9)

Add your solution and test expressions to the insertion-sort.scm file. 18.4.3 (Display page) Trace through the sort procedure. It has been our experience that students don't entirely understand the sorted procedure even after they've written it. Use the Modeler or the trace procedure to test your sorted procedure on the sentences (3 2 1), (3 1 2), and (2 3 1). (Alternatively, you could act it out with three of your classmates, or use your algorithm to sort a hand of playing cards.) Then explain how the procedure works to your t.a. or one of your classmates. 18.4.4 (Display page) Here's a buggy sort. Here's another version of sorted, again intended to return the result of arranging the numbers in the argument sentence into ascending order. For example, (sorted '(4 5 1 2 3)) should return the sentence (1 2 3 4 5). Unfortunately, it doesn't work. Figure out why, then answer the questions in the following steps.

(define (sorted sent) (cond ((empty? sent) sent) ((empty? (butfirst sent)) sent) ((< (first sent) (second sent)) ; first two are in the correct order (sentence (first sent) (sorted (butfirst sent)) ) ) (else ; first two are out of order (sorted (sentence (second sent) (first sent) (butfirst (butfirst sent)) ) ) ) ) ) 18.4.5 (Brainstorm) Find a sentence it doesn't sort. Find a sentence that sorted doesn't sort. That is, devise a sentence of numbers that, when given to the buggy sorted procedure as an argument, produces a value in which the numbers are not in increasing order. Also explain how you found it. 18.4.6 (Brainstorm) Describe completely all the sentences it doesn't sort. Describe, as completely as possible, the set of sentences that the buggy sorted procedure fails to sort. Then look at the descriptions of your classmates and think about how complete and correct they are. Make a note in the Extra Brain if you see that you missed something big. 18.4.7 (Brainstorm) Find the shortest possible fix. Fix the buggy sorted procedure, with as few changes as possible. Then describe the fix you made. Don't just post your code. Try to explain the changes you made and why you made them. Think about the fixes that your classmates suggest. If you find a really great one, you might want to make a note of it in the Extra Brain. Hint: the shortest possible fix will involve the insert procedure you just wrote. 18.5 A procedure's specifications are important to procedures that call it.(3 steps) 18.5.1 (Brainstorm) Give specifications for a longest-word procedure. Clint wants to find out if high-school students learn anything from their English courses. He proposes to measure this by comparing the longest word in sentences spoken by seniors to the longest word in sentences spoken by freshmen, using the following procedure:

(define (english-classes-help? senior-sent freshman-sent) (> (count (longest-word senior-sent)) (count (longest-word freshman-sent)) ) ) For example,

(english-classes-help? '(eschew obfuscation) '(be clear))

should return #t (and provide evidence that the senior had learned something from English class), while

(english-classes-help? '(hey dude) '(i am hungry))

should return #f and provide a counterexample. Write the specifications—a description of the input and the output—for the longest-word procedure. When describing the input and output, try to give as many useful details as possible. For example, we know the input can be a sentence, but does it make sense to take just any sentence? 18.5.2 (Brainstorm) Debug a longest-word procedure. Here's a buggy version of longest-word:

(define (longest-word sent) (cond ((equal? (count sent) 1) sent) ((> (count (first sent)) (count (first (bf sent)))) (longest-word (sentence (first sent) (bf (bf sent)))) ) (else (longest-word (bf sent))) ) ) Find the bug, and fix it by writing a working version. Look back at the specifications you wrote in the last step. Did this buggy version of longest-word violate those specifications? Make sure your fixed version agrees with them. 18.5.3 (Brainstorm) What caused the bug? What confusion on the part of the author of the buggy longest-word procedure probably led to the bug? 18.6 Homework(2 steps) 18.6.1 (Display page) Homework reminder, plus survey, plus discussion Homework http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 52 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Your compress assignment is due in prior to the next lab. Details follow in the next step. You should also go to bspace.berkeley.edu, log in there, go to the CS 3L site, and complete the "CS 3L post- exam1 survey". Finally, you should return to the discussion of the previous lab, "Change digit-values or sum-of-all?", and comment on the posts of two of your lab mates. 18.6.2 (Display page) Write compress Background

Data stored on computers can often be compressed to take less space. The compression process detects patterns in the data, and codes those patterns more compactly. (People who have trouble throwing things away find this very handy.) Picture data is especially appropriate for compression. Conceptually. a black-and-white picture is just a grid of black and white "dots". It can be represented by a sequence of 0's and 1's, with a 0 representing each white dot and a 1 representing each black dot. Pictures often contain large regions of a single color, however, and such a region can also be represented just a few values: a number representing the color, and one or two numbers saying how much of that color there is in the region. This technique can also be applied to sentences of 0's and 1's. A sequence of consecutive identical numbers in the sentence can be replaced by two values: the number of words in the sequence, and a single copy of the repeated number. Here's an example: uncompressed sentence compressed sentence (0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 1 1) (4 0 1 4 0 9 1)

Problem

Write a procedure named compressed that implements the process just described. You may assume that the argument to compressed is a sentence containing only 0's and 1's. The argument may be empty. The sentence returned by compressed will have several properties.

Its words (if any) are all nonnegative integers. Every occurrence of an integer greater than 1 is immediately followed in the sentence by a 0 or a 1. For example, compressed should never return the sentence (2 1 2) or (3 2 1). Consecutive 0's or 1's will not occur. A sequence of, say, five consecutive 0's would have been replaced by the values 5 and 0, and a sequence of two consecutive 1's would have been replaced by the values 2 and 1. Consecutive groups of 0's or 1's will not occur. For example, the sequence (4 1 5 1) represents a sequence of nine 1's that would have been compressed to (9 1).

Your procedure should only compress sentences that need compressing; for example, (compressed '(0 1 0 1)) should return (0 1 0 1). The compressed version of any sentence of 0's and 1's should be no longer than the sentence itself. Your procedure may call helper procedures; test these by themselves as well as in combination. If your program requires more than a half-page of code, however, you should rethink your solution. Include a comment with each of your procedures that describes its arguments and return values as specifically as possible. At least one of your procedures will be recursive. Avoid unnecessarily long or complex case analysis. Use reasonable names for procedures and place holders. Test compressed on at least one sentence in each of the following categories: a sentence ending with a group a sentence starting with a group of 1's of 1's a sentence ending with a group a sentence starting with a group of 0's of 0's a sentence starting with 1 0 a sentence ending with 1 0 a sentence starting with 0 1 a sentence ending with 0 1 a sentence containing consecutive compressible an empty sentence groups Put your solution and test expressions into a file named compress.scm in your hwk10 directory. 19 Bugs in complicated recursions, and two-stage 2009-10-08 ~ 2009-10- (5 recursions. 09 activities) 19.1 Review of tail recursion(4 steps) 19.1.1 (Display page) What is tail recursion? Tail Recursion

The term "tail recursion" is a common one, and often comes up in CS 3. We haven't yet focused on the concept in the lab materials; this short section will remedy that. Before defining tail recursion, recall the four things that are present in recursive procedures:

Base case(s): The problem is simple enough to be solve directly, or without recursive invocations. Recursive case(s): there are three pieces to each recursive case:

1. Divide the problem: Make the problem simpler in some way. One common way is to use the butfirst of a sentence. 2. Invoke the function recursively: Call the function recursively on the smaller/simpler part(s). 3. Combine the solutions: Combine the recursive solutions of the smaller parts together to form a solution for the whole problem.

In tail recursion, that "combining of solutions" is made as simple as possible: the recursive call on the sub-problem is made in such a way that it essentially solves the whole problem. The recursive solution, then, isn't really combined with anything, but can be returned directly as the solution to the whole. In practice, what this means is that

1. Each recursive call needs to keep track of the current "solution to the whole". Generally, this is in the form of another argument to the procedure. Accumulating recursions, which use a helper procedure with an extra argument to do the actual recursion, are often tail recursive. 2. The base case will return the "whole solution" that has been built up over each call. Usually, this means returning that argument in which the current solution has been passed on each recursive call. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 53 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

A recursion that is not a tail recursion is called an embedded recursion. 19.1.2 (Self Test) Which procedures are tail recursive? ;; returns the number of vowels in a word (define (num-vowels wd) (cond ((empty? wd) 0) ((vowel? (first wd)) (+ 1 (num-vowels (bf wd)))) (else (num-vowels (bf wd))) ))

;; returns the number of vowels in a word (define (num-vowels2 wd) (num-vowels2-helper wd 0))

(define (num-vowels2-helper wd so-far) (cond ((empty? wd) so-far) ((vowel? (first wd)) (num-vowels2-helper (bf wd) (+ 1 so-far)))) (else (num-vowels2-helper (bf wd) so-far)) ))

19.1.3 (Display page) Tail recursion versus accumulating recursion The defining feature of tail-recursive procedures is that the results of recursive calls are not combined in any way, but rather return the answer to the problem directly. The recursive calls won't stop until the answer is wholly known. Most often, this is done via an "accumulating recursion"; that is, where something is accumulated in a particular argument to the procedure over the recursive calls. However, they are not synonymous. There are tail recursions that don't need an extra accumulating argument:

;; a tail recursive procedure to return the first ;; n elements of a sentence (define (first-n sent n) (if (>= n (count sent)) sent (first-n (bl sent) n)))

And, there are procedures that use extra, accumulating arguments but do some combining on the recursive results. 19.1.4 (Brainstorm) Testing the efficiency of tail over embedded recursions Tail recursions are generally more efficient than embedded, because in the former Scheme doesn't have to keep track of all the combiners from previous recursive calls. Consider two (fairly meaningless) procedures, one tail and one recursive:

(define (count-to-embed n) (if (= n 0) 0 (+ 1 (count-to-embed (- n 1)))))

(define (count-to-tail n) (count-to-helper n 0))

(define (count-to-helper n so-far) (if (= so-far n) so-far (count-to-helper n (+ 1 so-far))))

Test these two procedures in your version of Scheme, comparing them when called with the same argument. At some point, the embedded procedure will crash your Scheme process, because it runs out of memory. Roughly, what size argument causes this? And, with arguments smaller than this, can you notice a difference between the speeds of the two procedures?

Note: to restart your Scheme process easily, in Emacs, move your cursor to the Scheme frame and type meta-x (hold the meta key down while typing x) followed by run-scheme, and enter. 19.2 Analyze a complicated (buggy) recursion.(5 steps) 19.2.1 (Display page) Here's the buggy code. Consider a procedure named 1-extra? that, given two words as inputs, should return true exactly when the first word is the result of inserting a single letter into the second word. Examples:

expression desired result (1-extra? 'HEAT 'HAT) true (1-extra? 'THAT 'HAT) true (1-extra? 'HATE 'HAT) true (1-extra? 'ABBC 'ABC) true (1-extra? 'AT 'HAT) false (1-extra? 'HAT 'HAT) false (1-extra? 'HATED 'HAT) false (1-extra? 'CHEAT 'HAT) false

A buggy version of 1-extra? appears below.

(define (1-extra? word1 word2) (cond ((empty? word1) #t) ((not (= (count word1) (+ 1 (count word2)))) #f) ((equal? (first word1) (first word2)) (1-extra? (butfirst word1) (butfirst word2)) ) (else (1-extra? (butfirst word1) word2)) ) )

The next several steps involve analyzing the buggy 1-extra?. You may wish to work on them with a partner. 19.2.2 (Brainstorm) Find arguments that 1-extra? doesn't work for. Provide a call to 1-extra? for which it does not perform as specified, that is, it returns true when false is the correct answer, or it returns false when true is the correct answer. 19.2.3 (Brainstorm) Describe arguments for which 1-extra? mistakenly returns true. Describe briefly in English the complete set of words wd for which the result of evaluating the expression (1-extra? wd 'HAT) is true, but wd is not the result of inserting a single character into the word HAT. Also describe how you got your answer. Note: it is possible that there are no words for which (1-extra? wd 'HAT) returns true incorrectly. Work on the next step for a while, then return to this step and check out your classmates' answers. If you see anything really neat, put it in http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 54 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

your notebook. 19.2.4 (Brainstorm) Describe arguments for which 1-extra? mistakenly returns false. Describe briefly in English the complete set of words wd for which the result of evaluating the expression (1-extra? wd 'HAT) is false, but wd is the result of inserting a single character into the word HAT. Also describe how you got your answer. Note: it is possible that there are no words for which (1-extra? wd 'HAT) returns false incorrectly. Work on the next step for a while, then return to this step and check out your classmates' answers. Add anything really neat to your notebook. 19.2.5 (Brainstorm) Describe the bug. Find a classmate to work with on this. Review the responses to the preceding two steps, summarizing the arguments in each of three categories:

those for which 1-extra? works, those for which it returns #f when it ought to return #t, and those for which it returns #t when it ought to return #f.

With your classmate, devise a general description of the bug. (This won't be just a description of how it fails in one or a small number of specific instance.) When you think you have a good description, post it. 19.3 Two-stage recursions(7 steps) 19.3.1 (Display page) Reverse the order of words in a sentence and letters in each word of the sentence. Consider the following procedure, which reverses the order of words in its sentence argument and the order of characters in each word in the sentence.

(define (thoroughly-reversed sent) (if (empty? sent) sent (sentence (thoroughly-reversed (butfirst sent)) (chars-reversed (first sent)) ) ) )

(define (chars-reversed wd) (if (empty? wd) wd (word (chars-reversed (butfirst wd)) (first wd) ) ) ) Test the code to produce some evidence that it works. 19.3.2 (Brainstorm) Why are two reversed procedures necessary? Having two versions of the reversed procedure seems too complicated. Why won't the following procedure work? (Don't just say what error occurs when you run it—give a more informative reason.)

(define (thoroughly-reversed sent) (if (empty? sent) sent (sentence (thoroughly-reversed (butfirst sent)) (thoroughly-reversed (first sent)) ) ) ) 19.3.3 (Display page) "Two-stage" recursion You can call procedures like thorougly-reversed a "two-stage" recursion, because there is an outer and an inner recursion. A very common application of two-stage recursions, especially in this class, is in situations where the outer recursion traverses a sentence, and the inner recursion traverses each word in the sentence. thoroughly-reversed is precisely of this type, and you can probably think of many more examples, like:

removing duplicates for each word in a sentence (the outer recursion traverses the sentence, and the inner recursion does dupls-removed translating a sentence of roman numerals, removing 'garbage' characters from words in a sentence

and so forth. 19.3.4 (Display page) Remove-letter Write a procedure remove-letter that takes two inputs, a letter and a sentence, and returns the sentence with all occurrences of the letter removed. For example:

(remove-letter 'e '(here is a sentence (hr is a sntnc with ==> with e in it) "" in it) (remove-letter 'e '(not any within)) ==> (not any within) (remove-letter 'e '()) ==> ()

Save your solution is the file two-stage.scm. (This is from the Fall 2005 second midterm) 19.3.5 (Brainstorm) Which alternative do you prefer, and why? Here was the first version of thoroughly-reversed:

(define (thoroughly-reversed sent) (if (empty? sent) sent (sentence (thoroughly-reversed (butfirst sent)) (chars-reversed (first sent)) ) ) )

(define (chars-reversed wd) (if (empty? wd) wd (word (chars-reversed (butfirst wd)) (first wd) ) ) ) Here's another version.

(define (thoroughly-reversed sent-or-wd) (cond ((empty? sent-or-wd) sent-or-wd) ((sentence? sent-or-wd) (sentence (thoroughly-reversed (butfirst sent-or-wd)) (thoroughly-reversed (first sent-or-wd)) ) ) (else ; sent-or-wd is a word (word http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 55 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(thoroughly-reversed (butfirst sent-or-wd)) (first sent-or-wd) ) ) ) ) Which version do you prefer, and why? Are they both two-stage recursions? 19.3.6 (Display page) You have seen several two-stage recursive procedures before this. Many of the recursive problems that you have worked on require two-stage recursion to solve them. For instance, recall remove-dupls:

(define (remove-dupls wd) (cond ((empty? wd) "") ((member? (first wd) (bf wd)) (remove-dupls (bf wd))) (else (word (first wd) (remove-dupls (bf wd)) )) ))

At first glance, this appears to be a "simple" recursion in the filtering pattern. Indeed it is. But, think about how the member? procedure must be written: it itself is a simple recursive procedure (of the testing pattern). So, remove-dupls is the outer recursion, and member? is the inner. When you are using member?, you can ignore that it is recursive and simply use it. This is because you are using abstraction. 19.3.7 (Display page) Write a more complicated two-stage recursion. Write pair-all, which takes a sentence and returns a sentence of all the pairs present in the first sentence. Think about how a solution can be broken up into an inner and an outer recursion. Looking carefully at the examples below may help. Put pair-all in the file utils.scm.

> (pair-all '(a b c d)) (ab ac ad bc bd cd)

> (pair-all '(spr ing ong ung)) (spring sprong sprung ingong ingung ongung)

(Note, in this version of pair-all, the words in the input sentence are not paired with themselves. In the first example above, the pairs aa, bb, and so forth are not included in the output sentence.) 19.4 A checklist for buggy recursive procedures(2 steps) 19.4.1 (Evidence) Here are some sources of bugs in recursive procedures. Here are things to consider when debugging a recursive procedure.

Symptom: infinite recursion

Does each recursive call make progress toward a base case? Generally, when debugging a recursive procedure whose argument is a word or sentence, you should be suspicious of a recursive call that doesn't involve the use of butfirst with that word or sentence. Similarly, with a procedure whose argument is a number and whose base cases involve 0 or 1, you should be suspicious of a recursive call that doesn't pass a smaller number as argument.

Symptom: crash by taking butfirst of an empty sentence or word.

Do your base cases adequately "guard" every use of first or butfirst? Whenever you use first or butfirst in a recursive procedure, you should have checked in a previous case that the relevant word or sentence isn't empty. Similarly, you should check that count of a sentence is at least two before evaluating first of butfirst, and so on.

Symptom: crash by supplying the wrong type argument to a procedure (e.g. a sentence to a procedure that expects a number or a word).

Are you returning consistent results in your various cases? A common error is to return a sentence when you should return a number or a word. (The sentence procedure does the right thing with some instances of the problem, but later in the course you'll have to worry about it more.) Always make sure every base case works. Even a little mistake in one can lead to a big error later. 19.4.2 (WebScheme) Debug the 1-extra? procedure Debug the 1-extra? procedure.

Again, consider a procedure 1-extra? that, given two words as inputs, should return true exactly when the first word is the result of inserting a single letter into the second word. For example:

expression desired result (1-extra? 'CHAT 'HAT) #t (1-extra? 'CHEAT 'HAT) #f

We have created eleven different buggy versions of 1-extra?. Can you give test cases that will catch all of the bugs? Try to use as few total test cases as possible. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. And, be sure to quote the arguments you give in your test cases! test case test case (1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

(1-extra? ) (1-extra? )

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 56 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(1-extra? ) (1-extra? ) Run your tests Bugs you didn't catch Got 'em all? 11

19.5 Homework(2 steps) 19.5.1 (Display page) Write occurs-in? Write and test a procedure named occurs-in? that, given two words as arguments, returns true when the first word occurs as a consecutive sequence of characters in the second word. Examples:

expression desired result (occurs-in? 'abc 'abcde) #t (occurs-in? 'abc 'xyabc) #t (occurs-in? 'ab 'axbc) #f (occurs-in? 'abc 'xy) #f

Put your solution and test expressions in a file named occurs-in.scm inside your hwk11 directory. 19.5.2 (Display page) Reading Reading

Read chapter 8 in Simply Scheme for next lab. 20 Procedures with procedures as arguments 2009-10-13 ~ 2009-10-14 (7 activities) 20.2 Broaden your view of placeholders.(8 steps) 20.2.1 (Display page) Here's how we've designed general procedures so far. Here's how we've designed general procedures so far.

Consider the creation of milk shakes as an analogy for making procedures. Here are some particular instances:

To make a strawberry milk shake, we combine strawberries and vanilla ice cream in a blender. To make a blueberry milk shake, we combine blueberries and vanilla ice cream in a blender. To make a raspberry milk shake, we combine raspberries and vanilla ice cream in a blender.

At some point, someone noticed the pattern:

To make a ___ milk shake, combine ___ and vanilla ice cream in a blender.

The ___ represents a placeholder. Using placeholders in this way lets us design a more general procedure that works for a large number of different arguments. You may have done a similar thing when you designed some of the procedures in the exercises on recursion. For example, in designing the down-to-0 procedure, you might have first designed individual procedures:

(define (0-down-to-0) '(0)) (define (1-down-to-0) (se 1 (0-down-to-0))) (define (2-down-to-0) (se 2 (1-down-to-0))) (define (3-down-to-0) (se 3 (2-down-to-0))) Again, one might notice the pattern:

(define (N-down-to-0) (se N (N-1-down-to-0))) We deal with this pattern by adding a placeholder (and a base case):

(define (down-to-0 n) (if (equal? n 0) '(0) (se n (down-to-0 (- n 1))) ) ) 20.2.2 (WebScheme) Placeholders can stand for procedures too! Placeholders can represent procedures too

Fill in the blanks below with the value returned by the call to mystery. If a call results in an error, fill in the blank with the word error. To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. If this step doesn't work for you, copy the definitions to STk to test your answers. Here are relevant procedure definitions: (define (combine a b) (* a (+ 2 b))) (define (mystery f) (f 3 1)) Scheme Expression Correct?

(mystery +)

(mystery combine)

(mystery member?)

20.2.3 (Display page) In Scheme, procedures are things you can manipulate In Scheme, procedures are objects that you can easily manipulate, similar to the ways you manipulate numbers and sentences. Above, you saw that procedures can be passed into other procedures as placeholders. Then, the passed procedure can be referred to by the name of the placeholder, and compared with equal? statements, invoked when put in the first position of an statement, and so forth:

(define (do-math func arg1 arg2) (if (and (equal? func /) (equal? arg2 0)) '(error! you can't divide by zero) ;; error! (func arg1 arg2) ;; no error - invoke the function ) )

Note that the "/" does not have a quote in front of it: we want to compare the placeholder to the actual divide procedure, not the name for it. You can return procedures from procedures: http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 57 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (get-func proc-name) (cond ((equal? proc-name 'plus) + ) ((equal? proc-name 'minus) - ) ((equal? proc-name 'times) * ) ((equal? proc-name 'divide) / ) (else 'huh?) ))

> ( (get-func 'plus) 3 5) 8 Procedures aren't words, however, so you can't put them into sentences:

> (sentence 'my 'procedures 'are + - / *) ERROR - Argument to SENTENCE not a word or sentence... In this course, we are most interested in the ability to pass procedures into other procedures and use them with placeholders. We have a name for a procedure that takes another procedure as argument: a higher-order function. (Yes, it should more properly be called a higher-order procedure, but we will use the two interchangeably). do-math, defined above, is a higher-order function; get- func is not. In the next activities, you will explore some of Scheme's built-in higher-order functions, and how to use them to easily solve tasks that would otherwise require fairly involved recursions. 20.2.4 (Display page) Compare two similar recursions... Consider the following two procedures. One is from the "Roman Numerals" code; the other returns the initial letters of the words in its sentence argument.

(define (digit-values roman-numeral) (define (acronym sent) (if (empty? roman-numeral) '( ) (if (empty? sent) '( ) (sentence (sentence (decimal-digit-value (first roman-numeral)) (first (first sent)) (digit-values (butfirst roman-numeral)) ) ) ) (acronym (butfirst sent)) ) ) )

What are the substantive differences in these procedures? (For instance, the fact that their placeholders are named differently isn't very meaningful). Consider how might a placeholder be used to represent the differences and form a more general procedure? 20.2.5 (Display page) Here's how to design an "applied-to-all" procedure. One way to increase the similarity between the digit-values and acronym procedures is to replace specialized names by more generic names: (define (digit-values sent) (define (acronym sent) (if (empty? sent) '( ) (if (empty? sent) '( ) (sentence (sentence (decimal-digit-value (first sent)) (first (first sent)) (digit-values (butfirst sent)) ) ) ) (acronym (butfirst sent)) ) ) ) Both procedures return the result of applying some other procedure to every word in the argument sentence. The two differences in the procedures appear in boldface. One difference is the names used in the recursive call; viewing the procedures more generally, however, we might chalk this up as a similarity—both procedures have a recursive call at the same place—rather than a difference. The other, more important difference is the procedure applied to (first sent). That difference can be represented as a placeholder to produce the following:

(define (applied-to-all proc sent) (if (empty? sent) '( ) (sentence (proc (first sent)) (applied-to-all proc (butfirst sent)) ) ) ) 20.2.6 (WebScheme) Supply a call to "applied-to-all". Provide a call to applied-to-all

Fill in the blank below with an argument for applied-to-all that would produce the value (10 5 1 1) That is, it would return the result of translating its Roman numeral argument to a sentence of decimal values. (The roman numeral code, version one, is here ). To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Correct?

(applied-to-all '(x v i i))

20.2.7 (Brainstorm) To quote or not to quote? The proper way to call applied-to-all to get the effect of digit-values is

(applied-to-all decimal-digit-value '(x v i i))

Why shouldn't decimal-digit-value be quoted? 20.2.8 (Display page) What's odd about this call? Every use of a procedure you've seen so far has involved calling the procedure. In the expression

(applied-to-all first '(mike likes cs3))

the first procedure is passed as an argument to applied-to-all without calling it immediately. Many students think this is weird. To them, a procedure is incomplete in some way without its arguments. Not in Scheme! 20.3 Experiment with "every".(7 steps) 20.3.1 (WebScheme) Use "every" with a builtin procedure. Define an acronym procedure

The operation of applying a procedure to each word in a sentence or to each character in a word (a mapping pattern) is so common that a procedure equivalent to applied-to-all is builtin to our version of Scheme. It's called every. Fill in the blank below with an argument for every that results in the acronym procedure returning the first initials of the words in the argument sentence. For example, (acronym '(royal air force)) should return (r a f). To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Correct? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 58 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (acronym sent) (every sent) )

20.3.2 (Display page) Use the Replacement Modeler with "every". The Replacement Modeler translates calls to every into simpler Scheme constructs. Model a call to acronym to display this translation. The trace tool can also be a useful way to see what every does. However, instead of tracing every, you should trace the procedure that you provide as a argument to every. Try that now. 20.3.3 (WebScheme) Use "every" with your own procedure. Redefine digit-values

Provide the body for a new version of the digit-values procedure that uses every and decimal- digit-value to return the desired sentence of decimal digit values. (The code from the roman numeral case study is here ). To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Correct? (define (digit-values roman-numeral) )

20.3.5 (Display page) Every and predicates Check your answer from the last step

Here's the definition of applied-to-all, which duplicates the functioning of every over sentence inputs:

(define (applied-to-all proc sent) (if (empty? sent) '( ) (sentence (proc (first sent)) (applied-to-all proc (butfirst sent)) ) ) ) If we make the following call:

(applied-to-all odd? '(1 2 3 4))

the procedure applied-to-all will error. What every and applied-to-all do is take a sentence or a word and return a sentence with the result of calling the procedure on each of the elements. If we call applied-to-all with the proc odd? then the result of applying odd? for each element will be either a #t or a #f, but you can't put #t or a #f in a sentence! (proc (first sent)) on the 4th line will return #t or a #f which will cause the procedure sentence on the 3rd line to error. 20.3.6 (Brainstorm) Do it again with a different set of arguments. The procedure proc below, when called with a sentence of numbers as argument, produces an error. Explain why by indicating which subexpression in applied-to-all produces an error when given the same arguments as proc is giving to every. Also explain what whoever coded proc is probably trying to do.

(define (proc num-sent) (every < num-sent) )

Again, here is the definition of applied-to-all:

(define (applied-to-all proc sent) (if (empty? sent) '( ) (sentence (proc (first sent)) (applied-to-all proc (butfirst sent)) ) ) ) 20.3.7 (Brainstorm) Give a good comment for the arguments to "every". Describe, as completely as possible, what arguments are appropriate for use with every. Then, as an example, describe all arguments to the procedure g below for which g will return a result without error.

(define (g b) (every b '(blue jay way)) ) 20.4 Derive "keep" and experiment with it.(8 steps) 20.4.1 (Display page) Generalize two procedures that "keep" only some of the words in their argument sentence. Consider the following two procedures. You might use the first to throw away non-numbers so you can add up all of the numbers in a sentence. You might use the other to get rid of empty words in a sentence (like in your number-name program). (define (numbers-only sent) (define (no-empty-words sent) (cond (cond ((empty? sent) '( )) ((empty? sent) '( )) ((not (number? (first sent))) ((empty? (first sent)) (numbers-only (bf sent)) ) (no-empty-words (bf sent)) ) (else (else (sentence (sentence (first sent) (first sent) (numbers-only (bf sent)) ) ) ) ) (no-empty-words (bf sent)) ) ) ) ) Define and test a procedure named my-keep that generalizes the two procedures above. My-keep will be given two arguments, a predicate and a sentence. The predicate argument will determine what words to keep in the argument sentence. 20.4.2 (Display page) The "my-keep" procedure turns out to be provided for you. The operation of "keeping" interesting words in a sentence (or, conversely, filtering out unwanted words) is another common operation. You might remember it as the filtering pattern. The builtin keep procedure is provided for this purpose. It works exactly the same as a correct version of the my-keep procedure you just wrote. 20.4.3 (WebScheme) Use the "keep" procedure. Implement choose-beatles

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 59 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Use the keep procedure to implement a procedure named choose-beatles. Choose-beatles will take a one-argument predicate procedure as argument, and will return a sentence of just those Beatles (John, Paul, George, and Ringo) that satisfy the predicate. Examples:

(define (ends-in-vowel? wd) (vowel? (last wd))) (define (even-count? wd) (even? (count wd))) > (choose-beatles ends-in-vowel?) (george ringo) > (choose-beatles even-count?) (john paul george)

To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. definition Correct? (define (choose-beatles pred) )

20.4.4 (Display page) See how the Replacement Modeler handles "keep". The Replacement Modeler translates keep into a fairly complicated expression. Model a call to choose-beatles and work through the translation; it may provide you with a richer understanding of how keep works. 20.4.5 (Self Test) Using keep with inapropriate arguments What will be the result of the following expressions?

(keep butfirst '(mike is a teacher))

(keep odd? '(1 2 3 four five))

20.4.6 (Brainstorm) Help a confused student. One of your classmates is surprised that

(keep butfirst '(mike is a teacher)) doesn't return

(ike s "" eacher) What do you think is the source of the student's confusion, and how would you try to help him or her get unconfused? 20.4.7 (Brainstorm) Help another confused student. Another of your classmates is surprised that

(keep butfirst '(mike is a teacher)) doesn't return

(mike is teacher) What do you think this student is confused about, and how would you try to help him or her out? 20.4.8 (Brainstorm) Give a good comment for the arguments to "keep". Describe, as completely as possible, what arguments are appropriate for use with keep. Then, as an example, describe all arguments to the procedure f below for which f will return a result without error.

(define (f a) (keep even? a) ) 20.5 Derive "accumulate" and experiment with it.(9 steps) 20.5.1 (Display page) Here is one kind of accumulation we've seen. Here are two kinds of accumulations we've seen.

We have seen a couple of ways to accumulate information about a sentence. Given below are two examples of one way. (define (sum-of-all num-sent) (define (sent-max num-sent) (if (= (count num-sent) 1) (if (= (count num-sent) 1) (first num-sent) (first num-sent) (+ (max (first num-sent) (first num-sent) (sum-of-all (bf num-sent)) ) ) ) (sent-max (bf num-sent)) ) ) ) These procedures differ only in the procedure used to combine the first word in the sentence with the rest. Here's a procedure that generalizes them by taking the combining procedure as an argument.

(define (my-accum1 accum-proc num-sent) (if (= (count num-sent) 1) (first num-sent) (accum-proc (first num-sent) (my-accum1 accum-proc (bf num-sent)) ) ) )

In the next step, you will implement sum-of-all and sent-max as calls to my-accum1. 20.5.2 (WebScheme) Use "my-accum1" to implement "sum-of-all" and "sent-max". Examine uses of accumulate

Fill in the blanks below to complete the redefinition of the sum-of-all and sent-max procedures. If a call results in an error, fill in the blank with the word error. To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Scheme Expression Correct? (define (sum-of-all sent) (my-accum1 sent) )

(define (sent-max sent) (my-accum1 sent) ) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 60 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(my-accum1 sent) ) If you miss any of these, put an entry in your notebook explaining the reason you missed it.

20.5.3 (Display page) Here's another kind of accumulation. Another kind of accumulation we've seen involves accumulating recursion. Here are sum-of-all and sent-max coded in this way. (define (sum-of-all num-sent) (define (sent-max num-sent) (sum-helper (max-helper (bf num-sent) (bf num-sent) (first num-sent) ) ) (first num-sent) ) )

(define (sum-helper num-sent sum-so-far) (define (max-helper num-sent max-so-far) (if (empty? num-sent) sum-so-far (if (empty? num-sent) max-so-far (sum-helper (max-helper (bf num-sent) (bf num-sent) (+ sum-so-far (first num-sent)) ) ) ) (max sum-so-far (first num-sent)) ) ) ) Here's a procedure that generalizes these two procedures.

(define (my-accum2 accum-proc num-sent) (accum-helper accum-proc (bf num-sent) (first num-sent)) )

(define (accum-helper accum-proc num-sent accum-so-far) (if (empty? num-sent) accum-so-far (accum-helper accum-proc (bf num-sent) (accum-proc accum-so-far (first num-sent)) ) ) ) 20.5.4 (Brainstorm) How do the two "my-accum" procedures differ? The my-accum1 and my-accum2 procedures accumulate information in different ways. You can observe this by passing – (the subtraction procedure) as the accumulating procedure argument, and by using the Replacement Modeler. Explain the difference between the two kinds of accumulation. 20.5.5 (Brainstorm) Which of "my-accum1" and "my-accum2" matches the builtin "accumulate"? Again, the process of accumulation is so useful that there is a builtin procedure named accumulate to implement it. Experiment to determine which of my-accum1 and my-accum2 matches the behavior of the builtin accumulate procedure, and describe how you figured it out. 20.5.6 (Display page) Implement "wordify". Examine another use of accumulate

Complete the definition of the wordify procedure. wordify returns the result of concatenating all the words in its argument sentence into a single word. Test your solution. Here is a sample interaction:

> (wordify '(a b "" c)) abc > (wordify '(302 47 9120)) 302479120

20.5.7 (Brainstorm) Use "accumulate" with inappropriate arguments. The procedure proc below, when called with a sentence of numbers as argument, produces an error. Explain why by indicating which subexpression in the appropriate my-accum procedure produces an error when given the same arguments as proc is giving to accumulate. Also explain what whoever coded proc is probably trying to do.

(define (proc num-sent) (accumulate < num-sent) ) 20.5.8 (Brainstorm) Give a good comment for the arguments to "accumulate". Describe, as completely as possible, the domain and range for accumulate. Also, describe what it does in your own words. 20.5.9 (Display page) Debug a use of accumulate A student is trying to write procedure to remove adjacent duplicates using accumulate, and is having problems. It should function like:

(rem-adj-dupls 'feed) ==> fed (rem-adj-dupls 'mississippi) ==> misisipi She has written:

(define (rem-adj-dupls wd) (accumulate rad-helper wd))

(define (rad-helper ltr so-far) (if (equal? ltr so-far) wd1 (word ltr so-far) ) )

Test her code by tracing the procedure rad-helper and calling rem-adj-dupls with the argument mississippi. Notice how the word gets "accumulated" in the second argument to rad-helper over successive calls to it. This is due to the inside out recursion, as shown in the definition of the similar procedure my-accum1 from above:

(define (my-accum1 accum-proc num-sent) (if (= (count num-sent) 1) (first num-sent) (accum-proc (first num-sent) (my-accum1 accum-proc (bf num-sent)) ) ) )

There are two things wrong with her rad-helper procedure. Use STk to fix them, and save the working code in the file utils.scm. 20.6 Use "every", "keep", and "accumulate" in combination.(4 steps) 20.6.1 (Display page) Here is a summary of "every", "keep", and "accumulate" Here's a summary of every, keep, and accumulate (adapted from Simply Scheme).

Every

Every transforms each element of a word or sentence individually. The result sentence usually http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 61 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

contains as many elements as the argument. Every's procedure argument is applied to everything in its word or sentence argument; thus the procedure argument itself takes one argument. Every is typically used for translation of words or letters to other values, for example as in the translation of Roman digits i, v, x, l, c, d, m to their decimal equivalents 1, 5, 10, 50, 100, 500, and 1000. A diagram of how every works appears below. The triangles represent the translated versions of the squares, which represent words or characters.

Keep

Keep selects certain elements of a word or sentence and discards the others. The elements of the result are elements of the argument, without transformation, but the result may be smaller than the original. Thus keep's procedure argument is also applied to everything in its word or sentence argument, but the results are used for a different purpose: not to transform the elements to something else, but to decide whether or not to "keep" them. A diagram of how keep works appears below. The X's represent elements of the word or sentence that are not kept in the result.

Accumulate

Finally, accumulate transforms the entire word or sentence into a single result by combining all of the elements in some way. Its procedure argument is a two-argument "combining" procedure. Here's a diagram.

20.6.2 (Display page) Here's a problem that uses these procedures together. Here's a problem that uses these three together.

Part a

Using every and accumulate, write and test a procedure named gpa that, given a sentence of grades, returns the corresponding grade-point average. Each grade will be one of A, B, C, D, or F. Assume that each course is 1 unit; thus the grade-point average will be the total number of grade- points divided by the number of courses. Put your solution and tests in a file named gpa.scm. For example, (gpa '(A A F C B)) would be the average of the five values 4, 4, 0, 2, 3, namely 2.6.

Part b

Now assume that grades of P and NP may also be included in the argument to gpa. These grades should not be counted in the average. Modify your solution of part a to remove P/NP grades (using keep) before doing the grade-point average calculation. 20.6.3 (Display page) Here's another problem. Here's another problem.

Write and test a procedure named true-for-all? that, given a predicate and a sentence, returns true if the predicate returns true for every word in the sentence. Examples:

> (true-for-all? even? '(2 4 6 8)) #T

> (true-for-all? even? '(2 6 3 4)) #F

Add this procedure to your utils.scm file that you created a while ago. 20.6.4 (Display page) And another problem. Write the procedure count-clubs, which takes a sentence of cards and returns the number of clubs in the "hand". Cards are represented by two-letter words, where the first letter is the rank and the second is the suit. So, kd is the king of diamonds, 2c is the two of clubs, as is the ace of spaces,

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 62 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

and so forth. For example,

(count-clubs '(kh 2c 3s qs 8c jc 3d))

should return 3. Don't use any helpers other than the procedures club? and suit below:

(define (club? suit) (equal? suit 'c))

(define (suit card) (last card)) 20.7 Homework(2 steps) 20.7.1 (Display page) Readings in Simply Scheme and discussion Readings and discussion

Read chapter 9 in Simply Scheme. (We will not cover the repeated procedure.) Also contribute a posting in the discussion in the next step. Next lab, contribute two comments to other people's posts. 20.7.2 (Discussion Forum) Discuss tips for debugging, writing, and understanding recursions. Tips for writing, understanding, and debugging recursions In the past few weeks you've written and analyzed lots of recursive procedures. Contribute some tips on what has made you most productive in writing, understanding, and debugging recursive code. Then, before your next lab, comment on the tips of two of your classmates, describing why their suggestions would or would not work for you. 21 More work with higher-order procedures 2009-10-15 ~ 2009-10-16 (5 activities) 21.1 Defining variables(5 steps) 21.1.1 (Display page) Another way to define a variable. There are three ways to define a variable.

You have seen one way to associate a value with a variable, namely the process of associating placeholders with arguments in the calling of a procedure. Another way, which you may have read about in chapter 7 of Simply Scheme, is a let statement. We won't worry about that here. A third way is the use of a define statement to define global variables, or variables whose value associations are accessible everywhere in a Scheme program (except where the definition is overridden by one of the other two methods). This is a simpler form of define:

(define variable-name value) such as

> (define x 15) x > x 15

We might have used such a definition in the "Difference between Dates" program:

(define month-names '(january february march april may june july august september october november december) )

Then we could have used month-names inside any of the procedures in the program. Any value works as the second argument to define:

> (define my-birthday '(august 17)) my-birthday > my-birthday (august 17)

> (define false #f) false > false #f

> (define e 2.71828182845905) e > (+ e 1) 3.71828182845905

> (define another-first-function first) another-first-function > (another-first-function my-birthday) august 21.1.2 (Display page) Here's another way to define a procedure-valued variable. Here's another way to define a procedure-valued variable.

Suppose now that we wanted to use the form of define just described with procedures; for example, we want to say

(define square something ) instead of

(define (square x) (* x x))

Whatever the "something" is, it must provide all the relevant information about the square procedure:

the number of arguments and names of corresponding placeholders; the expression whose value is to be returned by the procedure (its body).

Thus we need a way of saying

(define square "the procedure with one placeholder named x whose body is (* x x)" )

That's said in Scheme by using the lambda special form. Here's the format of a lambda expression:

( lambda ( placeholder names ) ( body ) )

We would then set up the association between the name square and the squaring procedure by http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 63 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

saying

(define square (lambda (x) (* x x)))

A good way to understand lambda is as "the procedure with placeholders ___ and body ___". This is exactly equivalent to the definition we had previously used:

(define (square x) (* x x)) The advantage of the form we've used so far is that the procedure is defined in the same way it's used; for example, the expression (square 3) is similar to the (square x) in the definition. The advantage of the form that uses lambda is the consistency in variable definitions—some Scheme textbooks avoid the use of the (define (square x) ...) usage completely! 21.1.3 (WebScheme) Experiment with lambda. Experiment with lambda

Add parentheses in the blanks below. (If this step is being uncooperative, copy the entry into your editor and add parentheses and test there. Remember, don't change any of the text other than to add parentheses). To see if you are right, press the arrow. If you see a green check, you got it. An invalid input message probably means unbalanced parentheses; you may copy the expression into the Editor to help get the parentheses right. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start.

Fill in parentheses to complete the definition of is-vowel?

define is-vowel? lambda char member? char 'aeiou

Fill in parentheses to check whether the character k is a vowel.

lambda char member? char 'aeiou 'k

Fill in parentheses to complete the definition of ends-in-vowel?

define ends-in -vowel? lambda wd is-vowel? last wd

Fill in parentheses to complete the definition of ends-in-vowel?

define ends-in-vowel? lambda wd lambda char member? char 'aeiou last wd

Fill in parentheses to check whether the word mike ends in a vowel.

lambda wd lambda char member? char 'aeiou last wd 'mike If you miss any of these, put an entry in your notebook explaining the reason you missed it.

21.1.4 (Brainstorm) Describe the difference between invoking and defining a lambda. Based on what you have learned so far about lambda, describe how we invoke lambda procedures in Scheme and how invoking is different from defining a lambda. Provide an example of each. 21.1.5 (Brainstorm) What's the result of accidental parentheses? Suppose you accidentally confused the two methods of defining a procedure, and produced the following definition of square:

(define (square) (lambda (x) (* x x)))

What are the properties of square? That is, what arguments does it take and what does it return? Provide an expression involving square that evaluates to 9.

21.2 Using "lambda"(4 steps) 21.2.1 (Display page) Why should we ever use lambda? Why should we ever use lambda?

We've seen that procedure-valued variables can be set up using either form of define. Suppose we're comfortable with the tried-and-true form that doesn't use lambda, as most people are; what incentive is there to switch?

One reason is that it may not be worth it to go to the trouble of naming a procedure. Suppose we have gone to the trouble of defining ends-in-vowel?:

(define (ends-in-vowel? wd) (member? (last wd) 'aeiou))

and we encounter a need for an ends-in-consonant? procedure. We could either define ends-in-consonant? explicitly,

(define (ends-in-consonant? wd) (not (member? (last wd) 'aeiou)))

or we could just cook up a lambda expression on the fly:

> (choose-beatles (lambda (wd) (not (ends-in-vowel? wd))) ) (john paul)

A second, more important reason is that we occasionally need to take advantage of the availability of some "extra" value in order to use every, keep, or accumulate. This often occurs when we are writing a procedure that has more than one placeholder, and the procedure that we are using with every, keep, or accumulate needs to use a placeholder's value as well as the item that it is passed. This is easier to think about in practice than in the abstract. As an example, consider a version of the builtin remove procedure in which we would like to use keep.

; Return the result of removing all occurrences of ; the given character from the given word. (define (my-remove char wd) (keep ___ wd) )

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 64 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

How would you fill in the blank? The next step asks you to think about this more. 21.2.2 (Brainstorm) Try to fill in the blank in the "my-remove" procedure. Without using lambda, try as many ways as you can think of to fill in the blank in the my-remove procedure below so that it behaves according to its comment. List each thing you tried and the behavior or error message that resulted.

; Return the result of removing all occurrences of ; the given character from the given word. ; For example, (my-remove 's 'mississippi) should return ; the word "miiippi". (define (my-remove char wd) (keep ___ wd) ) 21.2.3 (Display page) Here's how to make "my-remove" work. Here's how to make my-remove work.

Here's the version of my-remove that we're trying to complete.

; Return the result of removing all occurrences of ; the given character from the given word. (define (my-remove char wd) (keep ___ wd) ) Let's analyze what's needed.

In English, we want to keep all the characters that aren't char. Suppose we defined a not-equal? procedure:

(define (not-equal? x y) (not (equal? x y)))

We can't use not-equal? by itself,

(define (my-remove char wd) (keep not-equal? wd) )

for two reasons. Keep wants a predicate that itself takes one argument, and not-equal? takes two arguments. Anyway, we need to work char into the picture somehow, by saying "not equal to what". Keep's first argument has to be a procedure. Thus things like

(define (my-remove char wd) (keep (not-equal? char) wd) )

won't work. Because of the parentheses, (not-equal? char) is interpreted as a call to the not-equal? procedure that doesn't provide the two arguments it needs. What about making not-equal? less general, so that it specifically checks for not equal to char?

(define (not-equal-char? x) (not (equal? x char)))

We can then use not-equal-char? as keep's first argument, since not-equal-char? now takes only one argument. Unfortunately, when we try to use it, we get the error message along the lines of "char undefined variable". Thus we need a predicate procedure with one argument defined within my-remove so that we can use the placeholder char. Lambda to the rescue!

(define (my-remove char wd) (keep (lambda (ch) (not (equal? ch char))) wd) )

This is why lambda is cool. Just like all the other code you write inside my-remove, the lambda knows what char and wd are.

21.2.4 (Display page) Fix a misuse of lambda. Fix a misuse of lambda.

(exercise 9.4 in Simply Scheme) The following program doesn't work. Why not? Work with it in the interpreter. Then put the corrected version into the file 9.4.scm, along with an explanation of why the original didn't work.

(define (who sent) (every describe '(pete roger john keith)) ) ; see below

(define (describe person) (sentence person sent) ) It's supposed to work like this:

> (who '(sells out)) (pete sells out roger sells out john sells out keith sells out) (Pete Townshend, Roger Daltrey, John Entwistle, and Keith Moon were the original members of the band "The Who".) 21.3 Practice with higher-order procedures and lambda(6 steps) 21.3.1 (Evidence) Here are some strategies for using "every", "keep", and "accumulate". Designing programs with every, keep, and accumulate

Here are some tactics for designing with the higher-order procedures every, keep, and accumulate.

First, decide how the output compares to the input.

If they are the same structure (both words, or both sentences) and the same length, you probably want to use every. If they are the same structure (both words, or both sentences), and the output is possibly smaller than the input, you probably want keep. If the output is a combination of all the words in the input sentence or all the characters in the input word, you probably want accumulate.

One may observe that every and keep may be viewed as producing a combination of all the words in their input sentence or of all the characters in their input word. Indeed, every and keep may be implemented as calls to accumulate. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 65 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Suppose you decide to use every or keep. How do you decide on the procedure to use as its argument?

Let's start with every. We'll assume for simplicity that the second argument to every will be a sentence—of course, it can also be a word—and we'll call this argument sent. We'll call the procedure argument proc.

What are the characteristics of proc? First, it has to take exactly one argument. Second, its argument must be a word, since every will apply proc to every word in sent. Finally, proc's return value must be something that can be combined into a sentence. If we supply a word as argument to every, then proc must take a character as argument. What if proc needs two arguments? In that case, we need to use a lambda expression. A lambda expression is a procedure, but it can take advantage of the context in which it appears. For example, the lambda expression can itself have one placeholder, but its body can refer to a placeholder in an enclosing procedure.

Here's an example, the prepend-every procedure in Simply Scheme exercise 9.5. What's needed is a procedure that, given a word named prefix and a sentence, returns the result of prefixing prefix onto each word in the sentence.

> (prepend-every 's '(he aid he aid)) (she said she said) We start with a procedure header:

(define (prepend-every prefix sent)

We continue by observing that every is probably an appropriate higher-order procedure, and that it will apply some procedure to every word in sent:

(define (prepend-every prefix sent) (every _____ sent ) )

What's needed is a procedure that attaches prefix to the beginning of each word in sent. At first glance, that would require a procedure with two inputs, the prefix and the word. However, a lambda expression inside prepend-every can use all the placeholders that prepend-every makes available. In particular, it can use prefix without having it as a placeholder of its own. Here's the complete definition.

(define (prepend-every prefix sent) (every (lambda (wd) (word prefix wd)) ; prefix is prepend-every's placeholder sent) )

The keep higher-order procedure is used in pretty much the same way. Its procedure argument, like that of every, takes one argument. We'll call the procedure argument pred, since it's a predicate. If keep's second argument is a sentence, then pred will be applied to each word in the sentence. If keep's second argument is a word, then pred will be applied to each character in the word. The success or failure of this application determines whether the word or character appears in keep's result.

Suppose you decide to use accumulate. How do you decide on the procedure to use as its argument?

Again, let's give the arguments names. The procedure argument can be combiner. We'll assume for now that the second argument is a word, which we'll call wd. The combiner procedure will take two arguments, which represent the things being combined. The first is one of the characters in wd. The second is a "so far" argument, similar to what we saw in accumulating recursions. Combiner is applied to the character and the "so far" to get the next "so far" value. Here's an example, reversal of the characters in a word. We choose to implement this with accumulate. (An aside: why would every not work? What helper procedure would allow the use of every, at least on words whose characters are all different letters?) Here's a framework:

(define (wd-reverse wd) (accumulate (lambda (char reversed-so-far) _____ ) wd) ) How do we "accumulate" the character into the reversed word we have so far? We merely attach it to the end:

(define (wd-reverse wd) (accumulate (lambda (char reversed-so-far) (word reversed-so-far char)) wd) ) We urge you to test this using the Replacement Modeler, which may help solidify your understanding of how accumulate works. 21.3.2 (Display page) Complete a "words-in-both" procedure. Complete the code below by copying it to your editor, and replacing the blanks with a higher-order procedure (every, keep, or accumulate) and a lambda expression.

;; words-in-both takes two sentences of any length ;; and returns a sentence containing words that occur in ;; both of the input sentences. (define (words-in-both sent1 sent2)

( ______;; hof

______;;lambda

sent1) )

#| (words-in-both '(a b c) '(b c d e)) ;;=> (b c) (words-in-both '(a b c d) '(e f g)) ;;=> () ; more tests here

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 66 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

|#

21.3.3 (Display page) Complete a "dupls-removed" procedure. Complete the code below by copying it to your editor, and replacing the blanks with a higher-order procedure (every, keep, or accumulate) and a lambda expression.

;; dupls-removed takes a single word ;; and returns the result of removing characters that ;; appear more than once in that word (define (dupls-removed wd)

( ______;; hof

______;;lambda

wd) )

#| (dupls-removed 'volvo) ;;=> vol or lvo or vlo or olv (dupls-removed 'meaty) ;;=> meaty ; more tests here

|#

21.3.4 (Brainstorm) Why is "keep" not appropriate for implementing "dupls-removed"? Explain why keep is inappropriate for implementing dupls-removed. 21.3.5 (Display page) Complete a "hangman-status" procedure. Complete a hangman-status procedure

This is exercise 9.8 in Simply Scheme. In the game of hangman, one player has to guess a secret word chosen by the other player, one letter at a time. A Scheme procedure might help the players keep track of the letters guessed by printing the secret word, except with _ (underbar) characters for letters that haven't been guessed yet. For example, if the secret word is potsticker and the letters e, t, a, o, and i have been guessed, the procedure would return _ot_ti__e_ We'll call this procedure hangman-status.

(hangman-status 'potsticker 'etaoi) ;;=> _ot_ti__e_

Complete the code below by copying it to your editor, and replacing the blanks below.

;; (define (hangman-status secret-wd ltrs-guessed) (accumulate word (every

______

______) ) )

#| (hangman status 'potsticker 'etaoi) ;;=> _ot_ti__e_ (hangman-status 'meaty 'vegan) ;;=> _ea__ (hangman-status 'meaty "") ;;=> _____ ; more tests here

|#

21.3.6 (Brainstorm) Analyze a use of "accumulate". The following procedure implements the "insertion sort" algorithm.

(define (sorted wd) (accumulate insert wd) )

Sorted takes a word as argument, and returns the letters of the word in alphabetical order. For example,

(sorted 'potsticker) should return the word

ceikoprstt

Provide a good comment for the insert procedure. Your comment should describe the number of arguments, along with as much information about each argument and insert's return value as you can provide. 21.4 In conclusion(1 step) 21.4.1 (Display page) When do you have to use lambda? This is a question that many CS 3 students ask. In fact, some CS 3 students ask it several times. Memorize this, or write it down, or have it tattooed on your arm.

You need to use lambda if

You want to give a procedure to a higher-order functions, but that procedure needs more arguments than the higher-order function will give it. Example: we want a procedure that throws away all words in a sentence that are not duplicated:

(define (keep-only-duplicates sent) (keep (lambda (wd) (> (appearances wd sent) 1)) sent)) Here, the lambda needs both the word to keep or not keep and the whole sentence, but keep will only give it the word. You want to be able to return a custom-built function, like in repeated or make-adder That's it. If you ever get a Scheme-related tattoo, send us a picture! Then go get help.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 67 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

21.5 Homework(3 steps) 21.5.1 (Display page) Homework and reading Go back to the discussion in the last homework and make two comments on other people's posts. Then contribute a post to the discussion step that follows. Next time, contribute at least two comments to other students posts. Read part 3 of the "Difference Between Dates" case study, available here. Also, create two scheme files:

1. Save your solution to the "hangman-status" program in a file hangman.scm, and put it in a hwk15 directory. 2. Prepare a solution program to the "diagonal" problem described in the next step, saving it in a file named diagonal.scm in your hwk15 directory.

Submit these files in the usual fashion (i.e., from within unix by typing submit hwk15 inside the hwk15 directory). 21.5.2 (Display page) Write code that returns the "diagonal" of a sentence. Consider a sentence of N words, each containing N characters. We'll define the diagonal of this sentence as the word whose first character is the first character in the first word, whose second character is the second character in the second word, and so on. For example, the diagonal of the sentence

(ABCDE FGHIJ KLMNO PQRST UVWXY)

is AGMSY. The diagonal of a sentence can be constructed using every and a helper procedure named positions. We have provided a template for the diagonal procedure; you will need to fill it in correctly. The positions procedure, given a sentence of N words, returns the sentence (1 2 ... N). We have provided a buggy version of the positions procedure using accumulate below. You will need to fix it. First, though, study the buggy solution carefully. The lambda function provided to the accumulate contains a conditional that, depending on whether the right argument is a word or a sentence, operates differently. (This is the correct approach. The right argument will be a word for the first step of the accumulate; i.e., it will be the last element of the sentence that was initially passed to accumulate. But, the lambda is returning a sentence, because that is what it is trying to construct. As such, in every subsequent call to the lambda the right argument will be a sentence, which was returned by the previous evaluation of the lambda.) Note that the definition of positions does not require that each word in the sentence be the same length, and that that length be the same as the length of the sentence. The following calls should work:

(positions '(a b c d e f g)) --> (1 2 3 4 5 6 7) (positions '(the quick brown fox)) --> (1 2 3 4) Produce a solution organized as just described, by filling in the framework below. None of your code should be recursive. Put your solution in a file named diagonal.scm in the correct homework directory (detailed earlier).

;; Return the diagonal word for the given sentence. ;; If the sentence has N words, each of the words ;; will have N characters. (define (diagonal sent) ... (every ... (positions sent) ) ... )

;; Return the sentence (1 2 3 ... N), where N ;; is the number of words in the argument sentence. ;; This solution is buggy... (define (positions sent) (accumulate (lambda (left right) (if (word? right) (se (- (count sent) 1) (count sent)) ;first invocation (se (- (count left) 1) right))) ;all other invocations sent ) ) 21.5.3 (Discussion Forum) What makes lambda hard to understand? Reflect on lambda Many students learning Scheme have trouble with lambda. Suggest some aspects of lambda that might cause these problems, or previous experiences that might interfere with learning how lambda (and for that matter, higher-order procedures in general). Next time, respond to the posts of two of your classmates to suggest ways to counter these misconceptions or learning difficulties with lambda. 22 Working with larger programs that use higher-order 2009-10-20 ~ 2009-10- (5 procedures 21 activities) 22.2 Work with versions of the day-span program that use higher-order procedures.(7 steps) 22.2.1 (Display page) Rewrite "preceding-months-lengths". The code from Appendix D in part 3 of the Difference Between Dates case study is available here. Rewrite its preceding-month-lengths procedure to translate the sentence of month names to month numbers, then to shrink that to a sentence of relevant month numbers and translate that result to the desired sentence of month lengths. The code in the appendix uses the higher-order procedures every and keep. When you rewrite the procedure, you want to have it produce the same result by a different process, possibly using different higher-order procedures. For example, evaluating

(preceding-months-lengths 'june) would be represented by the following data flow diagram in the rewritten code:

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 68 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

22.2.2 (Brainstorm) Which version of "preceding-months-lengths" do you prefer? Which version of preceding-months-lengths—the original, or the version you just coded—do you prefer, and why? It's OK to say you don't have any preference, but you have to say why. 22.2.3 (Display page) Analyze another version of the "day-span" program. The next several steps involve a buggy version of the day-span program, available here. The bug results from the modification of a single symbol in the program. Paste the code into the Interpreter or stk to test it in order to find the bug. Note that this code represents a date as a word rather than as a sentence. A sample call to this version of day-span would thus be

(day-span 'january01 'december31) or (better)

(day-span (new-date 'january 1) (new-date 'december 31)) 22.2.4 (Brainstorm) For what dates does the buggy code produce the correct answers? Describe, as completely as possible, all inputs to the day-span procedure for which the buggy program returns the correct answer. 22.2.5 (Brainstorm) What is the bug? Which symbol in the program was incorrect, and what did you change it to in order to fix the bug? 22.2.6 (Brainstorm) How did you find it? Describe how you found the bug (what tests you tried, how you chose them, etc.). 22.2.7 (Brainstorm) Explain how the "precedes?" procedure works. The precedes? procedure in the program you just debugged uses accumulate. Describe how precedes? figures out whether its first argument precedes its second argument. 22.3 Experiment with the Tic-Tac-Toe program.(3 steps) 22.3.1 (Display page) Play the game. Play the game.

The code for the Tic-Tac-Toe program is available here. Its top-level procedure is named ttt. Ttt takes two arguments. The second names the player whose turn it is, either x or o. The first argument is the current board contents, described below. Ttt returns the square number in which the player to move should mark his or her X or O. Real-world Tic-Tac-Toe is played on a 3-by-3 board, for example,

x | o | x ---+---+--- | o | ---+---+--- o | x |

The ttt program represents a board configuration as a word that's formed by gluing the first row to the second to the third. It uses the underbar character to represent a square that hasn't yet been filled in. Its representation of the configuration above is xox_o_ox_. It numbers the squares as follows.

1 2 3 4 5 6 7 8 9

Ttt's return value is thus a number between 1 and 9. We play a game by making successive calls to ttt, with the player to move alternating between X and O. Here is how a game might start, with the player being X and the computer being O. result of ttt ttt call return explanation computer move x | | ---+---+--- (ttt | o | 'x______5 It chooses the middle square. ---+---+--- 'o) | |

x | | ---+---+--- (ttt We choose the opposite corner; it chooses the | o | o 'x___o___x 6 ---+---+--- 'o) last square in the second row. | | x

Your task

Play the remainder of the game. 22.3.2 (Display page) Here is how "ttt" represents a board configuration internally. Here is how ttt represents a board configuration internally. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 69 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

The ttt procedure immediately translates the word with x, o, and underbar characters into a representation that's easier to manage internally, namely a sentence of all ways to win. These are

the squares in the top row the squares in the middle row the squares in the bottom row the squares in the left column the squares in the middle column the squares in the right column the squares in the upper-left-to-lower-right diagonal the squares in the upper-right-to-lower-left diagonal

Each word in this sentence contains three characters and is referred to in the text as a triple. If a square is unoccupied, the character is its square number. If a square is occupied, the character is an X or an O, depending on which player has occupied the square. For example, if the middle row is completely unoccupied, the corresponding triple is 456. If there is an X in the middle square and an O in square 4, the triple is ox6. This representation is intended to make it easier to check for a win or a loss, and to evaluate the value of a prospective move. 22.3.3 (Self Test) Convert from word to triples and back. Give the sentence of triples that corresponds to the word o_xx_xoxo.

Give the word that corresponds to the sentence of triples (xo3 xx6 o8o xxo ox8 36o xxo 3xo).

22.4 Explore the helper procedures in the Tic-Tac-Toe program.(8 steps) 22.4.1 (Display page) Use diagrams to understand the helper procedures. Use diagrams to understand the helper procedures.

An important prerequisite to understanding how the ttt program works is to understand the role of the various helper procedures. (There are over twenty!) A good way to gather information about the helper procedures is to draw a call tree. The items in the tree represent the procedures; the "children" of an item in the tree are the procedures that that item calls. Here is the call tree for the ttt program.

The tree simplifies the grouping of helper procedures according to the tasks they help with. Another diagram is a data flow diagram, which shows what kind of arguments procedures are called with. Data flow diagrams can be useful design aids, as described in the "Roman Numerals" case study. They can also help in understanding a program. The arrows in a data flow diagram show what information is needed to transform one kind of data into another. An example appears below; it shows how the word _xo_x___ is translated to the triples (1xo 4x6 o89 14o xx8 o69 1x9 oxo) by the find-triples, substitute-triple, and substitute-letter procedures.

22.4.2 (Display page) Use "trace" to understand the helper procedures. Here are other ways to understand the helper procedures.

Another way to see how the pieces of a program interact is to use the trace procedure. Trace is given any number of procedure names as arguments. After trace is called, the named procedures produce information about their arguments and about their return value when they are called. Here is how to trace find-triples, substitute-triple, and substitute-letter using stk, along with the output that results from translating _xo_x_o__ into (1xo 4x6 o89 14o xx8 o69 1x9 oxo).

STk> (trace find-triples substitute-triple substitute-letter) okay STk> (find-triples '_xo_x_o__) .. -> find-triples with position = _xo_x_o__ .... -> substitute-triple with combination = 123, position = _xo_x_o__ ...... -> substitute-letter with square = 1, position = _xo_x_o__ http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 70 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

...... <- substitute-letter returns 1 ...... -> substitute-letter with square = 2, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 3, position = _xo_x_o__ ...... <- substitute-letter returns o .... <- substitute-triple returns "1xo" .... -> substitute-triple with combination = 456, position = _xo_x_o__ ...... -> substitute-letter with square = 4, position = _xo_x_o__ ...... <- substitute-letter returns 4 ...... -> substitute-letter with square = 5, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 6, position = _xo_x_o__ ...... <- substitute-letter returns 6 .... <- substitute-triple returns "4x6" .... -> substitute-triple with combination = 789, position = _xo_x_o__ ...... -> substitute-letter with square = 7, position = _xo_x_o__ ...... <- substitute-letter returns o ...... -> substitute-letter with square = 8, position = _xo_x_o__ ...... <- substitute-letter returns 8 ...... -> substitute-letter with square = 9, position = _xo_x_o__ ...... <- substitute-letter returns 9 .... <- substitute-triple returns o89 .... -> substitute-triple with combination = 147, position = _xo_x_o__ ...... -> substitute-letter with square = 1, position = _xo_x_o__ ...... <- substitute-letter returns 1 ...... -> substitute-letter with square = 4, position = _xo_x_o__ ...... <- substitute-letter returns 4 ...... -> substitute-letter with square = 7, position = _xo_x_o__ ...... <- substitute-letter returns o .... <- substitute-triple returns "14o" .... -> substitute-triple with combination = 258, position = _xo_x_o__ ...... -> substitute-letter with square = 2, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 5, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 8, position = _xo_x_o__ ...... <- substitute-letter returns 8 .... <- substitute-triple returns xx8 .... -> substitute-triple with combination = 369, position = _xo_x_o__ ...... -> substitute-letter with square = 3, position = _xo_x_o__ ...... <- substitute-letter returns o ...... -> substitute-letter with square = 6, position = _xo_x_o__ ...... <- substitute-letter returns 6 ...... -> substitute-letter with square = 9, position = _xo_x_o__ ...... <- substitute-letter returns 9 .... <- substitute-triple returns o69 .... -> substitute-triple with combination = 159, position = _xo_x_o__ ...... -> substitute-letter with square = 1, position = _xo_x_o__ ...... <- substitute-letter returns 1 ...... -> substitute-letter with square = 5, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 9, position = _xo_x_o__ ...... <- substitute-letter returns 9 .... <- substitute-triple returns "1x9" .... -> substitute-triple with combination = 357, position = _xo_x_o__ ...... -> substitute-letter with square = 3, position = _xo_x_o__ ...... <- substitute-letter returns o ...... -> substitute-letter with square = 5, position = _xo_x_o__ ...... <- substitute-letter returns x ...... -> substitute-letter with square = 7, position = _xo_x_o__ ...... <- substitute-letter returns o .... <- substitute-triple returns oxo .. <- find-triples returns ("1xo" "4x6" o89 "14o" xx8 o69 "1x9" oxo) ("1xo" "4x6" o89 "14o" xx8 o69 "1x9" oxo) If you're not careful, you might swamp yourself in trace output. Thus it is usually not appropriate to trace low-level procedures that are called a lot (for example, substitute-letter above). 22.4.3 (Display page) Use good comments to understand the helper procedures. Use good comments to understand the helper procedures.

Good comments can also help provide information about helper procedures. The ttt program code contains no comments, though the text of chapter 10 supplies most of the information that comments would include. You are encouraged to comment the procedures yourself:

what kinds of information are supplied in the arguments? what does the procedure return?

The next few steps ask about the kinds of input that will be provided to the procedures choose-win, i-can-fork?, and pivots; these procedures are incompletely described in the text. 22.4.4 (Self Test) What's a sample argument for "choose-win"? Which of the following sentences, during the course of a normal Tic-Tac-Toe game, might be supplied as an argument to the choose-win procedure?

22.4.5 (Brainstorm) Think about arguments to "choose-win". Why won't (xx3 2xx) ever be supplied as an argument to choose-win during the course of a legal Tic-Tac-Toe game? 22.4.6 (Brainstorm) Describe possible arguments for "i-can-fork?". Describe, as completely as possible, the triples arguments that might be supplied to the i-can- fork? procedure during the course of a legal Tic-Tac-Toe game, and briefly justify your answer. 22.4.7 (Brainstorm) What does the "pivots" procedure return? Describe, as completely as possible, the values that the pivots procedure might return during the playing of a legal Tic-Tac-Toe game. Explain how you figured this out. 22.4.8 (Brainstorm) Give a call to "ttt" that results in two calls to "pivots". Produce a call to ttt that results in pivots being called twice, and explain how the calls to pivots arise. 22.5 Homework(2 steps) 22.5.1 (Display page) Here is the homework assignment. For homework, go back to the last homework and make at least two comments to other people's posts. Then contribute a posting to the discussion in the next step. Next time, comment on the postings of two of your classmates in each discussion. This discussion topic addresses the issue of understanding Tic-Tac-Toe program. 22.5.2 (Discussion Forum) What examples work best to help someone understand the program? http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 71 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Devise a set of example calls to the procedures in the Tic-Tac-Toe program that would help someone come to better understand how the program works. Next time, comment on how well the calls devised by two of your classmates would help you, or someone like you, to understand the program. 23 The last of HOF: modifying Tic-Tac-Toe. 2009-10-22 ~ 2009-10-23 (2 activities) 23.1 Modify the Tic-tac-toe program.(6 steps) 23.1.1 (Display page) Modify the format of ttt's "position" argument. Modify the format of ttt's position argument.

Currently, the Tic-Tac-Toe program uses an underbar to represent a blank square. This is inconvenient because (a) one needs to hit the shift key in order to type an underbar, and (b) it is sometimes difficult to tell how many underscores one has typed. Fix the program to allow any of underbar, hyphen, equal sign, or asterisk to represent a blank square. After your revision, you will then be able to represent the board

x | o | ---+---+--- | | ---+---+--- | | x

in numerous ways, including xo-=**_*x, xo_-_-_-x, and xo******x. Put your revisions in a file named revised.ttt.scm. The code for the Tic-Tac-Toe program is available here. 23.1.2 (Display page) Figure out who is supposed to move. Figure out who is supposed to move.

In your revised.ttt.scm file, redefine ttt to take a single argument, namely the game configuration, and to compute the me argument to ttt-choose. This will be the player whose turn it is to move. If the number of X's on the board is equal to the number of O's, it's X's turn to move; if the number of X's is one more than the number of O's, it's O's turn; otherwise ttt should return #f. Two examples of how the revised code should behave are shown below. a call in the original program an equivalent call in the revised program (ttt '____x____ 'o) (ttt '____x____ ) (ttt 'o__xxo___ 'x) (ttt 'o__xxo___ ) 23.1.3 (Display page) Rewrite the "pivots" procedure. Rewrite the pivots procedure.

The current pivots procedure analyzes each pair of triples to see if they produce a "pivot" move. Another way to find the pivots is to check each open square to see if it's a pivot. In your revised.ttt.scm file, reorganize the pivots procedure by completing the framework below, and by supplying any necessary helper procedures.

(define (pivots triples me) (keep ___ '(1 2 3 4 5 6 7 8 9)) )

Include tests of the new pivots procedure in the revised.ttt.scm file. 23.1.4 (Discussion Forum) Make sure the position is valid Write a procedure called valid-position?, which takes one argument and returns #t if that argument is a legal tic-tac-toe position and #f if it is not. The argument can be anything, so make sure your program is careful. Assume that you are working with the original 3x3 board and that blank squares are only represented by _. Once you have posted your code, look for mistakes in programs other people have posted. If you find one, leave a comment that describes the problem. You should come back to this page later to see if anyone found a mistake in your code. 23.1.5 (Display page) Make the program use a slightly larger board. Make the program use a slightly larger board.

The book Winning Ways claims that it's possible to avoid a tie in Tic-Tac-Toe on any bigger board, even with just one extra square. Modify your revised.ttt.scm program so that the game is played on the following ten-square board. The new square should be square number 0.

+---+ | | +---+---+---+ | | | | +---+---+---+ | | | | +---+---+---+ | | | | +---+---+---+ Optional: Decide if either player has a winning strategy on the revised board. 23.1.6 (Brainstorm) Must diagonal triples still follow row/column triples? On page 165, Harvey and Wright comment on why they list the diagonals last in the triples list. Is this still necessary with the revised pivots procedure? Why or why not? 23.2 Homework(2 steps) 23.2.1 (Display page) Homework 1. Go back to the discussion in the last homework and make two comments on other people's posts for the discussion. 2. Then make an initial entry into the discussion below: "Reflect on your experience with higher order procedures".

Next lab session will cover lists. For preparation, read chapter 17 of Simply Scheme. 23.2.2 (Discussion Forum) Reflect on your experience with higher-order procedures. You've been confronted by a number of challenging exercises involving higher-order procedures. Problems you encountered included

confusing keep and every; using the wrong kind of procedure with keep, every, or accumulate; using the wrong sentence or word argument with keep, every, or accumulate; figuring out what processing to put in the procedure argument and what processing to put in the sentence or word argument;

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 72 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

keeping nested lambda expressions straight.

Describe which of these was hardest for you, and what you learned from earlier exercises that helped you with the later ones. Then respond to two of your classmates' posts with tips you have for managing uses of higher-order procedures. 24 Working with lists 2009-10-27 ~ 2009-10-28 (5 activities) 24.2 Here is an introduction to lists.(8 steps) 24.2.1 (Display page) Lists can contain anything! Lists can contain anything!

The data structures we've been working so far have been sentences and words. A word can contain only characters. A sentence can contain only words. Representing a collection of more complicated kinds of things—even boolean values!—has been either awkward or impossible. A list is a more general data structure. Its elements may be of any data type: booleans, words, sentences, or even procedures or other lists. 24.2.2 (Display page) Here's some terminology. Here's some terminology.

A list, like a sentence, is represented by an outer pair of parenthesis that encloses the list contents. When you take away the outer parentheses of a sentence, you're left with the words in the sentence. Similarly, when you take away the outer parentheses of a list, you're left with the elements of the list (which may be lists themselves). Here's an example: The list (((a b) c) d (e f)) has three elements:

the list ((a b) c); the word d; and the list (e f).

Operations we've used with sentences have list counterparts: sentence builds a sentence out of its list builds a list out of its arguments arguments empty? checks whether its sentence null? checks whether its list argument argument is the empty sentence. is the empty list. sentence? checks whether its argument is list? checks whether its argument is a a sentence. list. first returns the first word in its car returns the first element in its list sentence argument. argument. butfirst returns the sentence that cdr returns the list that results from results from removing the first word of its removing the first element of its list sentence argument. argument. list-ref returns the element at a given item returns the word at a given position position in a list. Positions are in a sentence. Positions are numbered numbered starting at 0. The first starting at 1. The first argument is the argument is a list, and the second is the position, and the second is the sentence. position. The quote procedure or the single-quote mark is used to take a list literally, as with sentences and words. Here is a sample dialog with stk.

STk> (car '(((a b) c) d (e f))) ((a b) c) STk> (cdr '(((a b) c) d (e f))) (d (e f)) 24.2.3 (WebScheme) Experiment with car and cdr. If this page doesn't work, use STk directly to test out the calls to car and cdr

Experiment with car and cdr

Give a combination of calls to car and cdr that will pick the list (2 3) from the list (1 (2 3) 4). Then give a combination of calls to car and cdr that will pick the list ((3 4)) from the list (1 (2 (3 4)) 5). Don't forget the closing parentheses for each expression. To see if you are right, press the pointer. If you see a green check, you got the right answer, otherwise you got it wrong. You will need to wait until you see the word "SchemeHandler" in the upper left corner of the page before you start. Desired Its Your expression Correct? value value

'(1 (2 3) 4) (2 3) ????

'(1 (2 (3 4)) 5) ((3 4)) ????

If you miss either of these, put an entry in your Extra Brain explaining the reason you missed it.

24.2.4 (Brainstorm) Analyze another access to part of a list. Explain why car and cdr are insufficient to pick the list ((2 3)) from the list (1 (2 3) 4). 24.2.5 (Display page) cons, list, and append build lists. Cons, list, and append build lists.

We had one sentence-building procedure, namely sentence. There are three list-building procedures, each of which specializes in a particular kind of list construction.

The cons procedure takes two arguments. The second is a list. The first is a new element for the list. Cons returns the result of attaching the new element as the first element of the argument list. Examples: expression result http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 73 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(cons 'a '(b (d e))) (a b (d e)) (cons 'a '( )) (a) (cons '( ) '(b (d e))) (( ) b (d e)) (cons '(b (d e)) '(b (d e))) ((b (d e)) b (d e)) The list procedure takes any number of arguments, of any type. It returns a list whose elements are the given arguments. Example: expression result (list 'a '( )'(b (d e))) (a ( ) (b (d e))) The append procedure takes two lists as arguments, and returns the result of gluing them together into one list. (One way to think of this is that append "erases" the inner parentheses). Examples: expression result (append '(a) '(b (d e))) (a b (d e)) (append '( ) '(b (d e))) (b (d e)) (append '(b (d e)) '(b (d e))) (b (d e) b (d e))

24.2.6 (WebScheme) Experiment with cons, list, and append. If this page doesn't work, use STk directly to test out the calls to the list generation procedures (making the window very wide will help see the desired result).

Experiment with cons, list, and append

In each of the following, fill in the first blank with one of cons, list, and append, and fill in the second blank with a quoted argument (list or word) to produce the given result. Desired Your Expression Correct? result result (all lists ( '(not created equal)) are not ???? created equal) ((all lists ( '(not created equal)) are) not ???? created equal) (lists (not ( '(not created equal)) ???? created equal)) ((lists) (not ( '(not created equal)) ???? created equal)) If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

24.2.7 (WebScheme) Analyze calls to cons, list, and append. If this page doesn't work, use STk directly to get the desired result. Sorry for any problems you have!

Experiment more with cons, list, and append

In each of the following, fill in the (quoted) arguments or leave them blank to produce the given result. Desired Your Expression Correct? result result

(cons ) ((a b)) ????

(list ) ((a b)) ????

(append ) ((a b)) ????

If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

24.2.8 (WebScheme) Deal with parentheses. Once again, if this page doesn't work, use STk directly to get the desired result.

Experiment with parentheses defining lists

Insert parentheses and quotes in each of the following expressions so that the result of evaluating each expression is the list ((1) (2 3)). Your Expression Correct? result

list 1 2 3 ????

cons 1 2 3 ????

cons 1 list 2 3 ????

If you miss any of these, put an entry in your Extra Brain explaining the reason you missed it.

24.3 Here are some things to look out for.(3 steps) 24.3.1 (Display page) Lists and sentences are different. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 74 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Lists are like sentences, but at the same time, they aren't ...

After going through a brief introduction to the list data structure, you are probably asking yourself, "Why are we using lists anyway? We use them in the same way as we do sentences!" This is a bit beyond the scope of this course, but you will learn, if you choose to continue on to CS 61A, that lists are much different than sentences in terms of structure. For now, all we want you to understand is that lists are not—we repeat, not—the same as sentences. The important thing to understand is that the different data types are associated with different procedures and constructors. For instance, sentences contain only words, are built with sentence, and are accessed with first, butfirst, or empty?. Lists, on the other hand, contain anything, are built with cons, list, or append, and are accessed with car, cdr, or null?. So a big hint to you is that whenever you encounter a problem on an exam, homework, or other activity that exclusively uses procedures associated with one data type, then stick with that data type! For example, if you use cons to make a list, don't use first to take it apart. 24.3.2 (Display page) Don't mix them up. Don't say we didn't warn you!

Now that you are clear about the difference between lists and sentences, you ought to know that interchanging the data types with the other type's constructors or procedures will not necessarily result in incorrect results, but will be something that we will be picky about. This is something we call a "Data Abstraction Violation," where a piece of code explicitly uses some data type, but also utilizes procedures or constructors associated with a different data type. The situation is similar to what you've seen with the "Difference Between Dates" code: using car to get the month name of a date "works", provided that dates are represented accordingly. Since the representation of a date may be changed, good programming practice says that you should use the accessors and constructors that go with the abstract type. Keep this in mind for projects or exams, since you will lose points for data abstraction violations. 24.3.3 (Display page) Dots are important! A detail about the cons operation that you may have overlooked is that its second argument must be a list. If you provide a word as second argument to cons, the Scheme interpreter prints the result with a dot (or period) before the word, for example:

> (cons 'abc 'def) (abc . def) This is almost certainly not what you want. In particular, this is not a two-element list, and will not be viewed as equal to the list (abc def). Keep your eyes peeled in the next few exercises for dots in your list structure, and check the corresponding cons operations for a valid second argument. 24.4 Try some more complicated exercises.(2 steps) 24.4.1 (Display page) Implement my-sentence. Implement my-sentence.

Unlike most Scheme procedures, the sentence procedure is very flexible about the types of its arguments, which can all be either words or sentences. Provide an implementation of the sentence procedure—name it my-sentence—that consists only of tests and calls to cons, list, and append. You can also use sentence? or word?. Assume that my-sentence takes only two arguments, and that each argument will only be a word or a sentence. All of the following example expressions should evaluate to (a b).

(my-sentence 'a 'b) (my-sentence '(a) 'b) (my-sentence 'a '(b)) (my-sentence '(a) '(b))

Put your solution and test expressions in a file named my-sentence.scm. 24.4.2 (Display page) Determine first and last names. Background

We've all seen form letters that start something like "Dear Michael Clancy:" and go on to say "You, Michael, can take advantage of this once-in-a-lifetime offer ..." Such letters are generated from a data base of names collected from a variety of sources. The names have to be analyzed before the form letters are generated, to avoid embarrassments like the following: name mistake John D. Rockefeller III "Dear Mr. III:" Martin Van Buren "Dear Mr. Buren:" Ken Griffey Jr. "Dear Mr. Jr.:" Madonna "Dear Ms. Madonna:"

Problem

Write a procedure named separate-names that splits a name into two parts: the corresponding last name and the remainder of the name (the first name and middle names). The argument to separate-names will be a nonempty list of the words of a name, last name first. Separate-names should return a list whose first element is a list containing the complete last name, and whose second element is a list containing the complete first name along with any middle names. Separate- names should check for the following special cases:

1. A single word should be treated as a first name. 2. "Van" or "de" appearing as the first word in the list should be combined with the following word to form a two-word last name. 3. "Jr" or "III" occurring after a last name should be ignored.

Thus, your procedure should return the following results: argument to separate-names result returned by separate-names (rockefeller iii john d) ((rockefeller) (john d)) (van buren martin) ((van buren) (martin)) (griffey jr ken) ((griffey) (ken)) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 75 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(madonna) (() (madonna)) (morrison van) ((morrison) (van)) (de moneybags iii biff ((de moneybags) (biff oglethorpe)) oglethorpe) (windsor charles philip arthur ((windsor) (charles philip arthur george) george) ) Note that despite condition 1, it is possible to provide only a last name as the argument to separate-names. The name (van buren) is an example. Your solution must handle such cases correctly; only when the argument consists of a single element should its first word be considered a first name. If you want more of a challenge, you can worry about names like James van de Graaff IV. Otherwise, assume the worst you need to worry about is Biff Oglethorpe de Moneybags III. Put your solution and test expressions in a file named separate-names.scm. 24.5 Homework(2 steps) 24.5.1 (Display page) Reading, etc. Read all of Simply Scheme chapter 17 for your next lab, except for the section "Functions that take variable numbers of arguments" on pages 292 and 293. Also contribute a posting, and comment on how the postings of two of your classmates would help you, in the discussion in the following step. 24.5.2 (Discussion Forum) Discussion Students often have trouble distinguishing between cons, list, and append. How will you avoid this confusion? 25 Generalized lists and tree recursion 2009-10-29 ~ 2009-10-30 (2 activities) 25.1 Generalized lists are...(5 steps) 25.1.1 (Display page) Here's the definition of a generalized list. We've seen that a list can contain any type of element, even another list. We'll refer to a list that contains lists that contain lists ... and so on as a generalized list. (Simply Scheme calls this an "arbitrarily structured list".) More formally, a generalized list is either empty, or it's a list whose elements are either non-lists or generalized lists. Note that this is a recursive definition. (Note: we use the term "non-list" rather than "word", here, because the items that we are referring to might be functions, or booleans, etc. For the majority of our examples in this course, however, you will work with words.) 25.1.2 (Display page) Here's what they look like. Sentences are just lists of words. Compared to lists of lists, they aren't really interesting. On the other hand, doing recursion on them is really easy. You just go from the first to the second to the third, and so on. Lists aren't always so easy. Take a look at the list

'(this (list (is really (((really)) deep))) (and confusing))

The first element of this list is the word this. The second element is the list (list (is really (((really)) deep))), and the last element is the list (and confusing). That's easy to see, right? How about looking at it like this:

Now (we hope) it is a little more obvious that there are three things in the list. 25.1.3 (Display page) Processing a generalized list The pattern for processing a generalized list reflects the recursive definition we stated before:

A generalized list is either empty, or it is a list whose elements are either non- lists or generalized lists.

(define (processed gen-list) (cond ((null? gen-list) ...) ((word? gen-list) ...) ;;you might also want to ask boolean? or procedure? (else ; we have a list (combine (processed (car gen-list)) (processed (cdr gen-list)) ) ) ) ) Note that the recursive case contains two recursive calls. Yes, this is tree-recursion. You will also hear the term car-cdr recursion, because of the way it is written. When the first element of the list in question is itself a list, the function recurses into that first element and into the remaining elements of the list in question. Another thing to notice: the parameter for these procedures is often called a "list" (as in gen-list), but for certain recursive calls may be a non-list (i.e., a word). Simply Scheme presents the generalized list counterpart of the appearances procedure. Deep-appearances counts the number of times a given word appears in a given generalized list. We assume the list only contains words and other lists. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 76 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(define (deep-appearances wd gen-list) (cond ((null? gen-list) 0) ((equal? wd gen-list) 1) ((word? gen-list) 0) ; a word that's not what we're looking for (else (+ (deep-appearances wd (car gen-list)) (deep-appearances wd (cdr gen-list)) ) ) ) ) 25.1.4 (Display page) Add 1 to each element of a generalized list Consider a procedure deep-add-1 which takes a generalized list in which every non-list is a number. deep-add-1 should return a generalized list, of exact same form as the input, in which each number is one greater. Copy the template below to your editor, and fill in the blanks with valid scheme code. Some test cases are also included below.

;; deep-add-1 takes a genlist of numbers, and adds 1 to each number (define (deep-add-1 L) (cond ((null? L) ______) ((number? L) ______) (else (______(deep-add-1 (car L)) (deep-add-1 (cdr L))) ) ) )

#|

(deep-add-1 '()) (deep-add-1 '(1 (2 3) ((4) 5) 6)) (deep-add-1 '((((((((((0)))))))))))

|# 25.1.5 (Brainstorm) Comment on the comment. The comment to deep-add-1 stated that it

...takes a genlist of numbers, and adds 1 to each number

However, when coded properly, deep-add-1 can successfully operate on more inputs than the comment above claims. What other types of inputs can it correctly operate on? 25.2 Work with generalized lists.(5 steps) 25.2.1 (Display page) Consider three ways to "flatten" a generalized list. Consider three ways to "flatten" a generalized list.

Given below are three procedures that are intended to "flatten" their nonempty generalized list argument, that is, return a list of all the words that occur in the list, in the same left-to-right order that they occur in the list. (This is exercise 17.12 in Simply Scheme.)

(define (flat1 gen-list) (cond ((null? gen-list) gen-list) ((word? (car gen-list)) (cons (car gen-list) (flat1 (cdr gen-list)))) (else (append (flat1 (car gen-list)) (flat1 (cdr gen-list)) ) ) ) )

(define (flat2 gen-list) (cond ((null? gen-list) gen-list) ((word? gen-list) (list gen-list)) (else (append (flat2 (car gen-list)) (flat2 (cdr gen-list)) ) ) ) )

(define (flat3 gen-list) (if (word? gen-list) (list gen-list) (append (flat3 (car gen-list)) (flat3 (cdr gen-list)) ) ) ) The next step asks you some questions about these procedures. 25.2.2 (Brainstorm) Analyze the three flattening procedures. 1. Of the three procedures, which ones correctly flatten a nonempty generalized list? 2. Which of the correct procedures requires the fewest recursive calls to flatten the list? 3. Point out the bug in each incorrect procedure.

Briefly explain your answers. 25.2.3 (Display page) One might analyze flat1 by tracing it by hand. Here's how one might start to analyze flat1

Given below is the code for flat1, copied from the previous step.

(define (flat1 gen-list) (cond ((null? gen-list) gen-list) ((word? (car gen-list)) (cons (car gen-list) (flat1 (cdr gen-list)))) (else (append (flat1 (car gen-list)) (flat1 (cdr gen-list)) ) ) ) )

We might start to trace it by hand as follows. If we call (flat1 '(this (list (is really (((really)) deep))) (and confusing))):

1. gen-list is not null. 2. The car of gen-list is a word. We know how to handle this, since it looks just like a sentence. cons the first of the list onto flat1 of the rest of the list. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 77 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

3. Now gen-list is ((list (is really (((really)) deep))) (and confusing)). 4. It's still not null. 5. The first thing isn't a word. 6. Now we have to flatten the car (by going along the down arrow), flatten the cdr, and put them both together using append.

7. Now you have two copies of flat1 going.

A less painful way to analyze this procedure would be use the trace procedure or the Replacement Modeler. 25.2.4 (Display page) Write complete-reverse. Write complete-reverse.

Without using higher-order procedures, write and test a procedure named complete-reverse that, given a generalized list argument, returns the result of reversing the list and all its sublists as well. (Don't reverse the characters in the words in the list.) Here are some examples. expression desired result (complete-reverse '(the quick brown fox)) (fox brown quick the) (complete-reverse '((the quick) brown fox)) (fox brown (quick the)) (complete-reverse '((the (quick brown)) fox)) (fox ((brown quick) the)) Put your solution and test expressions in a file named complete-reverse.scm. 25.2.5 (Brainstorm) Compare with this complete-reverse. Here's a version of complete-reverse that uses map.

(define (complete-reverse gen-list) (if (list? gen-list) (reverse (map complete-reverse gen-list)) gen-list) )

Compare and contrast this version with a complete-reverse that doesn't use map. Which version do you prefer, and why? 26 Advanced list processing 2009-11-03 ~ 2009-11-04 (3 activities) 26.1 Work with the member procedure.(5 steps) 26.1.1 (Display page) Semipredicates are a special kind of predicate. So far, almost all the predicate procedures you've encountered—for example, equal?, empty?, and word?—return either #t or #f. Sometimes, however, this leads to redundant processing. One example is the member? predicate, which given a word and a sentence tells us whether or not the http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 78 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

word appears in the sentence. If the call to member? returns #t, there are all sorts of other things we might want to ask: What's the position of the word in the sentence? What immediately follows the word in the sentence? To answer any of these questions, we would have to invent our own procedure that searches for the word in the sentence all over again, repeating work that member? had done before. For that reason, there are procedures in Scheme called semipredicates that return #f to indicate failure, but return some list structure to indicate success. These procedures take advantage of the fact that in Scheme, any value that's not #f is regarded as true. 26.1.2 (Brainstorm) Here's a brief digression into "true" and "false". A CS 3 student defines the following procedure to determine if its argument is the name of a weekend day.

(define (weekend? day-name) (equal? day-name (or 'saturday 'sunday)) )

What does (weekend? 'sunday) return, and why? 26.1.3 (Display page) Here's how member works. Here's how member works.

The member (not member?)procedure takes two arguments. The first can be anything; the second is a list. If the first argument is not an element of the list, member returns #f (in the same way as member? would, when not finding its word argument in its sentence argument). If the first argument is an element of the list, however, member returns the portion of the list that starts with the first argument. (Thus it's a semipredicate.) Here are some examples. expression returned value (member 'a '(bbb a c)) (a c) (member 'x '(bbb a c)) #f (member ((mike clancy) (emily '(mike clancy) watt)) '((clint ryan) (mike clancy) (emily watt)) ) (member 'clancy #f '((clint ryan) (mike clancy) (emily watt)) ) The last example shows that member merely compares its first argument to each element of the list using equal?. It doesn't try to look inside a list element. member and member? look almost the same. If they find what they are looking for, they return something that is true. If they don't, they return #f. This means that you can still use member with if and cond, just like you would have used member?. For example,

> (if (member? 'weasel (se 'dave 'barry 'thinks 'words 'like 'weasel 'are 'funny)) 'funny 'not-funny) funny

> (if (member 'weasel (list 'dave 'barry 'thinks 'words 'like 'weasel 'are 'funny)) 'funny 'not-funny) funny

However, member and member? are not the same. Member works on lists, while member? works on words and sentences. Also, member returns more information than member?. Here are some examples:

> (member? 'weasel '(dave barry thinks words like weasel are funny) #t

> (member 'weasel '(dave barry thinks words like weasel are funny) (weasel are funny)

> (member? 'w 'weasel) #t

> (member 'w 'weasel) Error: bad list in member 26.1.4 (Display page) One application of member is up-to. One application of member is up-to.

Since member tells you more than member?, you can do more interesting things with it. Here is an example. Write a procedure named up-to that is given anything as a first argument and a list whose elements are all different as the second argument. If the first argument is not an element of the list, up-to should return #f. If the first argument is an element of the list, up-to should return the portion of the list that starts with the first element and ends with the argument element. (Thus up-to is a semipredicate.) expression returned value (up-to 'a '(b a c)) (b a) (up-to 'x '(b a c)) #f (up-to ((clint ryan) (mike '(mike clancy) clancy)) '((clint ryan) (mike clancy) (jieae goo)) ) (up-to 'clancy #f '((clint ryan) (mike clancy) (jieae goo)) ) Don't use recursion or higher-order procedures. The builtin reverse procedure will be useful, though. Put your solution and test expressions in your utils.scm file. 26.1.5 (Display page) Another is determining that one thing precedes another. Another is determining whether one thing precedes another.

A list can be regarded as an ordering of its elements. The member procedure comes in handy as a way to see if one item precedes another in this ordering. Write a procedure named precedes? that's given a list and two elements of the list as arguments. Precedes should return true (i.e. anything that's not #f) if the first element precedes the second in the list. Examples:

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 79 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

expression returned value (precedes? '(sun mon tues wed thurs fri sat) 'sun 'sun) #f (precedes? '(sun mon tues wed thurs fri sat) 'mon 'fri) anything true (precedes? '(sun mon tues wed thurs fri sat) 'fri 'mon) #f Don't use recursion or higher-order procedures; just take advantage of the power of member. Put your solution and test expressions in your utils.scm file. 26.2 Work with higher-order list procedures.(12 steps) 26.2.1 (Display page) The builtin higher-order procedures for lists are map, filter, reduce, and apply. The builtin higher-order procedures for lists are map, filter, reduce, and apply.

The higher-order procedures you've seen already have list counterparts: sentence/word higher-order procedure list higher-order procedure every map keep filter accumulate reduce Some notes: The word "filter" suggests removal of list elements. However, it really acts like keep, retaining all elements of its list argument that satisfy its predicate argument. The word "reduce" is mathematical terminology. The apply procedure is subtly different from accumulate and reduce. Apply takes two arguments, a procedure and a list. It essentially "cons"es the procedure to the front of the list, then evaluates that expression. For example, (apply max '(3 1 4 2)) gives the same result as (max 3 1 4 2). The length of the list argument should match the number of arguments expected by the procedure argument. Apply is useful in situations involving procedures that take any number of arguments, particularly

+, * max, min append Here are a couple of examples:

;; Return the largest value in a list of numbers. (define (list-max L) (apply max L) )

;; Return the result of gluing together all the sentences ;; of the argument, a list of sentences. (define (flatten-one-level L) (apply sentence L) )

Apply is thus similar to accumulate and reduce. The main difference is that the procedure argument to accumulate and reduce must take two arguments, and the accumulation is done sequentially from the end of the sentence or list; apply in these situations takes advantage of its procedure argument's ability to process the list all at once. If we redefined the builtin max to take only two arguments,

(define (max x y) (if (> x y) x y))

(apply max '(3 1 4 2)) would no longer work, while (accumulate max '(3 1 4 2)) would still return 4. 26.2.2 (Display page) Map can be used as a testing tool. Map can be used as a testing tool.

The map procedure provides a neat way to test some other procedure on a lot of test values at once. For example,

(map decimal-value '(ix viii mmclxv))

returns (9 8 2165). (Every would have worked here instead of map.) The next exercise generalizes this technique, using the day-span procedure from the "Difference Between Dates" case study. 26.2.3 (Display page) Use map (perhaps with apply) to test day-span. Use map to test your code conveniently

Fill in the blank in the following expression to test the day-span procedure on the given pairs of dates. You may also find apply useful. The result should be (365 1 29).

(map (lambda (______)

______)

'(((january 1) (december 31)) ((may 1) (may 1)) ((february 1) (march 1)) ) )

If you miss this, put an entry in your Extra Brain explaining the reason you missed it. 26.2.4 (Display page) Map can take multiple list arguments. Map can take multiple list arguments.

So far, we've seen every and map used only with one-argument procedures. One can, however, provide a procedure argument that takes more than one argument, along with multiple lists that supply the arguments for the procedure. Here are some examples: expression result (map + (11 102 1003) '(1 2 3) '(10 100 1000) ) (map list ((raymond chetty) (jennifer tsang) (emily '(raymond jennifer emily) watt)) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 80 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

'(chetty tsang watt) ) Here's an application of this technique.

1. First write a list version of the 0-up-to procedure you wrote earlier in the course. Given a nonnegative integer n, 0-up-to should return a list that contains the integers from 0 up to n; thus (0-up-to 3) returns (0 1 2 3). Don't use sentence; use cons or list or append instead. 2. Now write a procedure named diagonal (similar to what you wrote for an earlier homework). Given a list of n lists, all of length n, diagonal returns the elements on the upper-left to lower- right diagonal, namely the first element in the first list, the second element in the second list, and so forth. For the list of lists

((A B C) (D E F) (G H I))

diagonal should return (A E I). Here's a framework for diagonal:

(define (diagonal list-of-lists) (map ___ list-of-lists (0-up-to (- (length list-of-lists) 1)) ) )

Put your solution procedures and test expressions in a file named list-diagonal.scm.

26.2.5 (Display page) Determine the driest city given a table of city rainfall data. The driest-city problem.

Write a procedure called driest-city that, given an argument that contains information about cities and annual rainfall amounts, returns the name of the city that gets the least annual rainfall. For this exercise, assume that the argument list contains two-word sentences, each of the form

(city rainfall) Thus an example call would be

> (driest-city '((concord 22) (kentfield 35) (san-francisco 25) (san-jose 22) (needles -50))) needles

Don't use recursion for your solution. Put it and your test expressions in a file named driest-city.scm. 26.2.6 (Brainstorm) Compare solutions to driest-city. Two approaches that use higher-order procedures to solve the driest-city problem are given below.

(define (driest-city rainfall-info-list) (car (reduce (lambda (info1 info2) (if (< (rainfall info1) (rainfall info2)) info1 info2) ) rainfall-info-list) ) ) and

(define (driest-city rainfall-info-list) (car (filter (lambda (info) (= (rainfall info) (apply min (map rainfall rainfall-info-list)) ) ) rainfall-info-list) ) ) )

1. Which of the two approaches did your solution resemble more? 2. Which approach do you prefer, and why?

26.2.7 (Display page) Exclude holidays from day-span. Exclude holidays from day-span.

Write a procedure named day-span-no-holidays whose arguments include a list of holiday dates in addition to the "early date" and the "later date" that the day-span procedure takes. Day-span-no- holidays should exclude from the day count any dates in the holiday list that are in the period spanned by the early and late date arguments. Assume that the holiday list doesn't contain any duplicate dates. Here are some examples. expression desired result (day-span-no-holidays '(january 1) 362 '(december 31) '((january 1) (march 1) (december 31)) ) (day-span-no-holidays '(january 1) 2 '(january 3) '((january 1) (march 1) (december 31)) ) Don't change the day-span code. Don't use recursion. The precedes? procedure, written below, will be helpful.

;;precedes ;;INPUTS: two sentences ;;REQUIRES: each sentence be a date (first element a valid ;; month name, second element a day number appropriate for that month) ;;RETURNS: #t if the first date comes before the second, #f otherwise ;;SIDE-EFFECTS: none ;;EXAMPLE: (precedes? '(april 24) '(october 24)) ==> #t ;; (precedes? '(december 8) '(september 15)) ==> #f

(define (precedes? date1 date2) (> (day-span date1 date2) 1)) 26.2.8 (Brainstorm) Analyze a different kind of keep/filter. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 81 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Analyze a different kind of keep/filter.

Consider the different-filter procedure shown below. It is listed with an implementation of the builtin filter for comparison; differences are in boldface. (define (different-filter pred? L) (define (builtin-filter pred? L) (cond (cond ((null? L) '( )) ((null? L) '( )) ((pred? L) ((pred? (car L)) (cons (cons (car L) (car L) (different-filter pred? (cdr L)) ) ) (builtin-filter pred? (cdr L)) ) ) (else (else (different-filter pred? (cdr L)) ) ) ) (builtin-filter pred? (cdr L)) ) ) ) What's the difference between the predicate used with different-filter and the predicate used with filter? 26.2.9 (Display page) Use different-filter to implement words. Use different-filter to implement word filtering.

One implementation of a procedure to return a list of all the words in a list is

(define (words L) (filter word? L) ) Copy the procedure below, and modify it so that it has the same effect as the version above.

(define (words L) (different-filter ______L ) )

You will need to copy the different-filter procedure into STk to test this:

(define (different-filter pred? L) (cond ((null? L) '( )) ((pred? L) (cons (car L) (different-filter pred? (cdr L)) ) ) (else (different-filter pred? (cdr L)) ) ) )

26.2.10 (Display page) Use different-filter to implement dupls-removed. Use different-filter to implement dupls-removed.

Recall the dupls-removed procedure, which returns the result of removing duplicate elements from its list argument. Fill in the blank to complete the implementation of dupls-removed. Copy the procedure below to STk, and modify it so that it has the same effect as dupls-removed.

(define (dupls-removed L) (different-filter ______L ) )

You will need to copy the different-filter procedure into STk to test this:

(define (different-filter pred? L) (cond ((null? L) '( )) ((pred? L) (cons (car L) (different-filter pred? (cdr L)) ) ) (else (different-filter pred? (cdr L)) ) ) )

26.2.11 (Brainstorm) What's interesting about different-filter? It appears that different-filter can do what filter does, plus more. What accounts for the extra functionality? What might be a reason that filter is built-in, but different-filter isn't? 26.2.12 (WebScheme) Work with a list of procedures. Work with a list of procedures

First, set up a list of two-argument procedures (like list-ref, +, or cons. )

(define proc-list )

Then, fill in the blanks in the following procedure.

;; Given a nonnegative integer n and two other values x and y ;; as arguments, apply the nth procedure in proc-list to x and y. ;; Assume that n is less than the length of proc-list and that ;; x and y are the correct type for the procedure being applied. ;; Example: ;; if proc-list contains the procedures list-ref, +, and cons, ;; (apply-nth-proc 0 '(a b c) 1) should return b. ;; (apply-nth-proc 1 3 5) should return 8. ;; (apply-nth-proc 2 'a '(b c)) should return (a b c). (define (apply-nth-proc n x y) (apply

) )

Fails for ... Correct? ????

If you miss this, put an entry in your Extra Brain explaining the reason you missed it.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 82 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

26.3 Work with tables.(5 steps) 26.3.1 (Display page) Here's how to set up and use an association list. Here's how to set up and use an association list.

It is often the case that we want to associate pairs of values, with one item in each pair being used to look up the other. Some examples:

a Roman digit with its decimal value; a month name with the number of days in the month; a book title with its author; a word with its meaning.

In Scheme, a good way to store these associations is in a association list (sometimes called an a-list for short). Each element of an association list is itself a list. The first element of that list is a term to look up; the rest of the list is the "meaning" or value associated with that term. Here are tables for each of the above examples:

((i 1) (v 5) (x 10) (l 50) (c 100) (d 500) (m 1000)) ((january 31) (february 28) (march 31) (april 30) (may 31) (june 30) (july 31) (august 31) (september 30) (october 31) (november 30) (december 31)) (((the color purple) (alice walker)) ((three kingdoms) (luo guanzhong)) ((i robot) (isaac asimov)) ((simply scheme) (brian harvey) (matt wright)) ) ((window fenetre) (book livre) (computer ordinateur) (house maison) (closed ferme) (pate pate) (liver foie) (faith foi) (weekend (fin de semaine)) ((practical joke) attrape) (pal copain))

Applications for such tables are so common that Scheme provides a builtin lookup procedure named assoc. Assoc takes two arguments, a term to look up and a table to look it up in. The table is organized as just described, namely as a list of entries, with the first word of each entry being something to look up. Assoc returns the first entry in the table whose car is equal to the term being looked up. If there is no entry in the table corresponding to the term, assoc returns #f. (Thus assoc is a semipredicate.) Here are some uses of assoc.

> (define month-table '((january 31) (february 28) (march 31) (april 30) (may 31) (june 30) (july 31) (august 31) (september 30) (october 31) (november 30) (december 31)) )

> (define roman-digit-table '((i 1) (v 5) (x 10) (l 50) (c 100) (d 500) (m 1000)) )

> (define book-table '(((the color purple) (alice walker)) ((three kingdoms) (luo guanzhong)) ((i robot) (isaac asimov)) ((simply scheme) (brian harvey) (matt wright)) ) )

> (assoc 'may month-table) (may 31) > (assoc 'm roman-digit-table) (m 1000) > (assoc 'q roman-digit-table) #f > (assoc '(i robot) book-table) ((i robot) (isaac asimov)) 26.3.2 (Display page) Complete the definitions... Complete the recursive and HOF implementations of assoc below (by copying the page to STk):

(define (recursive-assoc x table) (cond ((null? table) #f) ((equal? x ______) ______) (else (recursive-assoc x (cdr table))) ) )

(define (hof-assoc x table) (let ((result (filter (lambda (entry) (equal? x (car entry))) table) )) ______; might need more than one line here ))

#| (define *code* '((1 a) (2 b) (3 c) (3 not-this) (4 d)) ) (recursive-assoc 1 *code*) (hof-assoc 1 *code*) (recursive-assoc 4 *code*) (hof-assoc 4 *code*) ; note, your code shouldn't return (3 not-this) (recursive-assoc 3 *code*) (hof-assoc 3 *code*) ; should return #f below (recursive-assoc 5 *code*) (hof-assoc 5 *code*) |# 26.3.3 (Display page) Improve the case study code. Improve the case study code.

Replace the days-in-month procedure in the "Difference between Dates" program with a version that uses assoc. Do the same with the decimal-digit-value procedure in the "Roman Numerals" program. (Don't forget to test your solutions.) 26.3.4 (Display page) Update a table. Update a table.

Write a procedure named update-table that takes three arguments: a table, a term, and a new value to be associated with that term. If the table does not contain an entry for the term, return the result of constructing an entry and including it in the table. If the table does contain an entry for the term, return the result of replacing its associated value with the argument value. Here are some examples. expression desired result (update-table '((i 1) (v 5) (x 10) (l 50)) ((i 1) (v 5) (x 10) (l 27)) 'l 27) (update-table '((i 1) (v 5) (x 10) (l 50)) ((i 1) (v 5) (x 10) (l 50) (c 100)) 'c 100) The order of table entries doesn't matter, so in the second example, update-table could return ((c

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 83 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

100) (i 1) (v 5) (x 10) (l 50)) or even ((c 100) (i 1) (l 50) (v 5) (x 10)). Put your solution and test expressions into your utils.scm file. 26.3.5 (Display page) Here's a summary of ways to avoid long conds. Here's a summary of ways to avoid long conds.

We have seen two ways to replace long cond expressions by more concise calls to built-in list processing procedures. Here's a summary.

A long cond that essentially translates a small integer to some other value can usually be replaced by a call to item or list-ref. For example,

(define (number-name small-number) (cond ((= small-number 1) 'one) ((= small-number 2) 'two) ... ((= small-number 18) 'eighteen) ((= small-number 19) 'nineteen) ) ) can be replaced by

(define (number-name small-number) (item small-number '(one two ... eighteen nineteen)) ) or

(define (number-name small-number) (list-ref '(one two ... eighteen nineteen) (- small-number 1) ) )

(Note that list-ref's position is 0-based, and the order of its arguments is different from that of item.) A long cond that essentially translates one value to another can usually be replaced by a call to assoc. For example,

(define (teen-value name) (cond ((equal? name 'eleven) 11) ((equal? name 'twelve) 12) ... ((equal? name 'eighteen) 18) ((equal? name 'nineteen) 19) ) ) can be replaced by

(define (teen-value name) (cadr (assoc name '((eleven 11) (twelve 12) ... (eighteen 18) (nineteen 19)))) )

27 Sequential programming 2009-11-05 ~ 2009-11-06 (3 activities) 27.1 Side effects and sequential programming(10 steps) 27.1.1 (Display page) Functional programming: a big picture In functional programming, programs are written by composing procedures, passing the return value from one procedure as an argument for another. A functional program communicates with the user through the arguments and return value of the outermost procedure. The functional procedures used in this manner are used purely for the way they transform their arguments into their return value. Functional programming, however—at least as much of it as we've seen thus far in CS 3L—has some limitations. 27.1.2 (Brainstorm) Limitations of functional programming Using what we've learned so far in CS 3L, we are unable to do either of the following:

write a procedure of no arguments that alternately returns 0 and 1; determine how many times a given procedure has been called.

Explain why. 27.1.3 (Display page) State State

Scheme's knowledge about the leftover effects of past computations is called its state. Changes to the program state are called side effects. So far, we have not seen any ways to change state directly. However, we have seen some situations where we change state indirectly: state how to change it whether or not to print trace output when a procedure is call trace or called untrace whether or not a variable is defined use define Harvey and Wright note that

[T]he notion of state contradicts functional programming. Earlier in the book, we emphasized that every time a function is invoked with the same arguments, it must return the same value. But a procedure whose returned value depends on state—on the past history of the computation—might return a different value on each invocation, even with identical arguments.

27.1.4 (Display page) Sequence and input/output Sequence and input/output

In programming thus far, we have seen that an expression

(+ (f 3) (g 3))

always returns the same answer regardless of whether f or g is executed first. For some operations, however, the sequence matters. The next few activities explore the use of sequential programming in the context of input and output operations—communication with the user. You'll see sequential programming in your final project. Chapter 20 in Simply Scheme is a good source of further information.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 84 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

27.1.5 (Display page) Printing, and the begin form Printing and the begin form

The two printing procedures that we will look at are display and show. Both take a single argument and print it to the listener, as if that were the return value being shown. display doesn't force a new line after printing, while show does. Consider:

> (define (converse me you me-say you-say) (cond ((empty? me-say) 'the-end) (else (display me) (display ": ") (show (car me-say)) (display you) (display ": ") (show (car you-say)) (converse me you (cdr me-say) (cdr you-say)) ) ) )

converse > (converse 'fred 'joe '(hello (how are you) (me to) goodbye) '((hello to you) fine (that is great) later) )

fred: hello joe: (hello to you) fred: (how are you) joe: fine fred: (me to) joe: (that is great) fred: goodbye joe: later the-end >

Some important points:

The sequence of displays and shows are very clearly not functional programming. There is no composition of the return values; in fact, display and show don't even have known return values. (In STk, they return "okay", as does a cond without an else statement does sometimes). This is sequential programming. The conversation has to occur, sequentially, in a particular order. Because of the way a cond statement is formatted, we could put several scheme expressions in sequence. The return value for that case is the last expression (in this case, the recursive call). When you need to do sequential programming within a single expression, use the begin form:

(begin (do-first-side-effect) (do-second-side-effect) (do-last-side-effect-and-return-what-this-returns) )

To print several things on one line, use several display statements. Use show on the last thing to print on the line so that the next thing to be printed will be on a new line.

When the procedure wants to print punctuation and spaces, it surrounds them in double quotes and makes a string. A string is a datatype in Scheme that can be printed: you have seen them sometimes when working with words (when they are empty, or start with a number, etc.).

The the-end that is printed at the end of execution is the return value for the converse procedure. Be sure to understand how this appearing in the listener is different than the rest of the conversation.

27.1.6 (Display page) "for-each": a higher-order function for sequential programming Ordering matters in sequential programming. The special form for-each is used in similar situations to map -- in fact, it takes the same parameters as map. For-each, however, guarantees that each element of the parameter list will be tended to in order. map makes no such promise. In:

(map square '(1 2 3))

The square of 3 may occur before the square of 2. This would be wrong for an expression like:

(map show '(print these in order)) ; wrong

Rather, use for-each:

(for-each show '(print these in order)) ; right!

27.1.7 (Display page) Print a tree, prettily ... Consider the tree *h7* defined in this file. Once defined in scheme, scheme will print it out in an ugly way:

> *h7* ((henry the 7th) ((arthur prince of wales)) ((henry the 8th) ((mary the 1st)) ((elizabeth the 1st)) ((edward the 6th))) ((margaret the 1st) ((james the 5th) ((mary queen of scots) ((james the 6th of scotland and 1st of england) ((henry frederick)) (elizabeth ((charles louis)) (rupert) (sophia ((george the 1st)))) ((charles the 1st) ((charles the 2nd)) (mary ((william the 3rd))) ((james the 2nd) ((mary the 2nd)) (anne) ((james francis edward - the old pretender) ((charles edward - the young pretender)) ((henry cardinal of york)))) (elizabeth) (anne) (henry) (henryetta)))))) (mary (frances ((lady jane grey)))))

Finish writing a procedure print-tree that takes a tree like *h7* and prints it to the screen nicely. It should print every node on a new line, with the children of a parent indented in 3 spaces to the right from where the parent was printed. So, the first part of *h7* should look like:

(henry the 7th) (arthur prince of wales) (henry the 8th) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 85 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(mary the 1st) (elizabeth the 1st) (edward the 6th) (margaret the 1st) (james the 5th) (mary queen of scots) (james the 6th of scotland and 1st of england) ...

The partial program is here:

(define (name tree) (car tree)) (define (children tree) (cdr tree)) (define (leaf? tree) (null? (children tree)))

(define (print-tree tree) (print-tree-help tree 0 3) )

;; depth is the number of generations -- for the initial tree it is 0; ;; for the children of the initial tree, it is 1; for their children, 2; ;; and so on. ;; indent is the number of spaces to move over for each generation (define (print-tree-help tree depth indent) (if (leaf? tree) ;; finish both cases here...

) )

;; you might find this procedure helpful: it prints n spaces (define (display-spaces n) (cond ((> n 0) (display " ") (display-spaces (- n 1))) (else (display "")) ) )

27.1.8 (Display page) Get user input A nice procedure for gathering user input from within a procedure is read-line. It takes no arguments, but when invoked halts execution of the procedure while waiting for the user to type something and press enter. The read-line procedure then returns whatever the user typed:

(define (better-converse) (show (list-ref '((tell me about yourself) (that is interesting) (you do not say) (tell me more) (please say more about that) (I never heard something like that before!) ) (random 6) ) ) (let ((what-he-said (read-line))) (if (equal? what-he-said '(arggh)) (show '(oh goodbye then)) (better-converse))))

Try it out, and change it as you see fit. Some points of interest:

The first time you call read-line, you are likely to have to call it twice. (Simply Scheme explains this on page 357.) The example above doesn't do this.

Read-line returns a sentence.

27.1.9 (Display page) The "read-eval-print" loop The "read-eval-print" loop

The top level of the Scheme interpreter consists of a repetition, or loop, of three actions:

1. reading a Scheme expression from the user; 2. evaluating that expression; and 3. printing the result.

This is clearly an example of sequential programming, since it makes no sense for the printing to occur before the evaluation or for the evaluation to occur before the expression input. We have seen that expression evaluation—say, of a display or a show—may itself produce output, and sometimes it's difficult to tell what part of the program produces a given line of output. The last thing printed will be what the print step in the read-eval-print loop produces; everything before that comes from the evaluation of output procedures. 27.1.10 (Brainstorm) "okay" The word "okay" is printed by STk as the result of evaluating an if or cond that hasn't supplied a complete set of cases. For example:

> (if (> 3 4) 'hello) okay Is "okay" a word? Explain why or why not. (Some experimentation with STk may be required. 27.2 Using "random"(5 steps) 27.2.1 (Display page) The "random" procedure The random procedure

The random procedure is used to generate random numbers; each time it is called, it returns a (possibly) different integer. That's a hint that it must rely on internal state to decide what value to return. random takes a single argument, an integer, which is the upper bound on the range of integers from which random will draw. (The lower bound is always 0, and is inclusive, unlike the upper). So,

(random 3)

will return one of 0, 1, 2.

(random 10)

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 86 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

will return an integer between (and including) 0 and 9.

(random 1)

however, will always return 0. This is the only argument that guarantees a certain result from random! The random procedure is not a standard part of Scheme, but is commonly provided in Scheme programming environments. Both STk and Dr. Scheme use the same format. 27.2.2 (Self Test) Some expressions using random Which expression will simulate rolling a 6-sided die?

Which expression will return a decimal number between 5 and 7, inclusive?

27.2.3 (Display page) Look at the distribution of random return values. The random function is supposed to return a uniform distribution, which means that every outcome within the range is as likely as every other outcome. If you were to make a bar plot of the return values from (random 10), each bar should be the same height. The following code is a way to check on this distribution:

;; k between 0 and 10 (define (dist-check k) (dist-check-helper k 10000 0 0) )

(define (dist-check-helper k num-trials iteration sofar) (cond ((= iteration num-trials) (/ sofar num-trials) ) ((< (random 10) k) (dist-check-helper k num-trials (+ 1 iteration) (+ 1 sofar)) ) (else (dist-check-helper k num-trials (+ 1 iteration) sofar) ) ) )

Try calling dist-check with values between 1 and 10. (Using map, you can do all ten calls with just one Scheme expression.) It will return the proportion of returns values from calls to (random 10) that were less than the argument. So, you would expect the call

(dist-check 5)

to return a number very close to 0.5. How good is STk's random procedure? 27.2.4 (Brainstorm) How good is "random"? Use the dist-check procedure to look in more detail at the distribution of the return values from the random procedure. Some things you might do include:

Change the number of trials to a (much) larger number Look at different ranges (i.e., 0-99, 0-99999, and so forth) Write code to automate dist-check, calling it once for every possible value in the range.

Report on what you did, and what you saw, below. 27.2.5 (Display page) Use "random" to shuffle a deck of cards. Consider the following method to create a standard deck of 52 cards, where each card is a list of rank followed by suit.

(define (new-card rank suit) (list rank suit)) (define (rank card) (car card)) (define (suit card) (cadr card))

(define *all-ranks* '(ace 2 3 4 5 6 7 8 9 10 jack queen king)) (define *all-suits* '(clubs diamonds hearts spades))

(define (new-deck) (reduce append (map (lambda (rank) (map (lambda (suit) (new-card rank suit) ) *all-suits*) ) *all-ranks*) ) )

Invoking new-deck will create a boringly ordered deck of cards, starting with (ace clubs), followed by (ace diamonds), and so forth. Using random, write shuffled which takes a deck of cards and returns a deck with the cards in a random order. The strategy to use is simple:

1. Assign a random number to each card in the deck. It is probably easiest to make a new list where the first element the random number and the second is the card. Use a really big random number so you aren't likely to have ties among the 52 cards. 2. Sort the new list according to the random number. 3. Extract the cards from the new list to make the shuffled deck.

Higher order functions will be the easiest way to implement steps (1) and (3). For step 2, remember the insertion sort you wrote some time ago:

(define (sorted sent) (if (empty? sent) '() (insert (first sent) (sorted (bf sent)))))

(define (insert item sent) (cond ((empty? sent) (se item)) ((> item (first sent)) (se (first sent) (insert item (bf sent)))) (else (se item sent))))

You will need to modify this in two ways: to work on lists, rather than sentences; and to compare parts of items rather than entire items. That is, you'll need to compare the random number parts of the pair of card and random number. Save your code for shuffled in a file cards.scm. 27.3 Putting it together: Monty Hall(5 steps) 27.3.1 (Display page) What is the Monty Hall problem? The Monty Hall problem is based on the old Let's Make a Deal television show, and became famous

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 87 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

because of how often it tricks people (mathematicians and lay people alike) into a wrong conclusion.

Briefly, it goes something like this: You (a contestant) are shown three closed doors. Behind one of the doors is a nice new car; behind the other two are goats. You, of course, don't know which door contains the car. You pick one of the three doors. Monty Hall, the smiling yet vaguely creepy host of the show, opens one of the other doors to reveal that it contains a goat. You are now given a choice: should you switch your pick to the other still-closed door, or keep your original choice? (Assume, for the sake of argument, that you want the car, rather than the other goat.)

Think about this problem for a bit. Should you switch, or should you not switch, or does it not matter one way or the other? 27.3.2 (Brainstorm) Switching doesn't matter, of course! Most people are confident that switching doesn't matter. Actually, you are much more likely to get the car if you do switch. There are many ways to think about this problem. In our experience, most of these ways fail to convince people! This page describes a few. This page contains an game that lets you try out the problem one pick at a time. Which do you think is best, and why? 27.3.3 (Display page) Finish the code... Below is a partially complete Monty Hall simulation program. When finished, the procedure monty- hall will take no arguments and will ask the user how many times they want to simulate the game. It will then do that simulation, both with the switching strategy and without. It should make a nice report, looking something like:

There were 1000 trials of each strategy. The switching strategy won 657 times. (Thats a percentage of 0.657). The holding strategy won 332 times. (Thats a percentage of 0.332). Capiche?

This is a simulation program, designed to run many, many trials in short order. You won't be asking the user for his/her choice (i.e., whether to switch or not) each time. The template code is available here. The central procedure is simulate-single, which runs one trial (with either the switching or not-switching strategy). Look at the nested let statements, which essentially set up the choices for the various doors (the car door, the initial choice, etc) sequentially. It returns #t if the contestant won the car, which it determines by comparing the car door to the final door choice. Understanding this procedure, and the procedures it calls, is crucial for understanding the simulation. In order to run the simulation, you will need to edit or write:

the ask-user-for-number procedure, to ask the user how many simulations to run. Recall, you may have to call read-line twice (see pages 356-358 in Simply Scheme). the simulate-many procedure, so that it prints out a report in the format above. the random-element procedure. Make sure to test this repeatedly so you are sure that it is capable of returning any element in the list (e.g., the first and last elements).

27.3.4 (Display page) Try some things. Once you are finished with the simulation, try it out. Does that report look right? The simulation is written so that you can easily change the number of doors, by changing the value of the global variable *doors*. Try this. 27.3.5 (Brainstorm) Does the program help with understanding? Did helping write this program help you get a feel for why switching is a good idea in the Monty Hall problem? Why or why not? Also include an honest assessment of how well you understand what the program is doing -- this is certainly a factor! 29 CS 3 projects 2009-11-09 ~ 2009-12-04 (5 activities) 29.1 CS 3 Projects: general information(1 step) 29.1.1 (Display page) Project information Projects and short problems

This document provides information about your last assignment in CS 3L: the big project. Included are details about the check-offs, working with partners, and other things of importance. There are three project assignments to choose from:

Connect Four Make the computer player smarter and choose the appropriate internal representation for the classic game of Connect Four. Blocks World Write the "smarts" of an artificial intelligence program that understands english commands to manipulate colored blocks. Yukon Complete the implementation of a user-playable version of the Yukon solitaire card game.

Descriptions of each project are in additional steps following this one. All, we hope, are interesting applications of programming; all will challenge you as well. For some students, the project may be too challenging. Those students may instead choose to do three short problems. The short problems, we hope, will be equally interesting, and will focus more directly than the projects on techniques you will need to know for the final exam (lists, tree recursion, and higher-order procedures). Thus time spent working on the problems that you don’t turn in solutions for will not be wasted. The only penalty for doing short problems instead of a project is that your course grade is capped at B+.

Due dates

There are four important dates in this assignment: three check-offs, and the final due date.

1. First check-off. At the end of lab on Thursday/Friday, November 12 or 13 (whenever you have lab), you must explain to your t.a. which project or short problems you plan to work on along with the following information: who, if anyone, you're working on it with; how you plan to split the work between members of your partnership if you're working with a partner; and which parts of the project you plan to have ready for the next progress check. If you do not do this during your lab, you will lose 10% of your total project score. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 88 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

2. Second check-off By Thursday/Friday, November 19 or 20 (whenever you have lab), you must display significant progress on the project: some procedures coded and tested, with a fairly detailed plan for proceeding on the rest. (The individual project writeups have suggestions for what to provide.) We are looking for about 25% of the code completed. If you're doing short problems, you need to have at least one of them solved. If you do not meet this milestone during your lab, you will lose 45% of your total project score. 3. Third check-off In lab on Tuesday or Wednesday, December 1 or 2, you must show your t.a. a mostly complete program, or, if you're doing short problems, show your t.a. solutions for at least two of the problems. Again, if you do not do this, you will lose 45% of your total project score. 4. Final due date Your completed project program/short problem solution collection is due at the end of the day (11:59pm) on Monday, December 7. Submit it as "project" or "short.problems", whichever is appropriate. If you still have grace hours left from the miniprojects, you may use them here. The number of grace hours remaining for a partnership is the average of the number that the partners have.

Even if you submit a perfect project, if you miss these three deadlines, you will get no points.

Grading

The project is worth 16 course points, which works out to 8% of the points on which your final grade will be based. Half of the points will be awarded based on project correctness and adherence to specified requirements; the other half will be awarded for displayed correctness (test cases), readability, and the general case you make that your program works correctly. The project checkoffs mentioned above will also provide points, contributing toward a factor by which your project grade will be multiplied: the points your project earns will be multiplied by the fraction of the checkoff points you earned before being counted toward your course grade. (For example, if you earn 8 out of the 10 points for the three checkoffs, your project grade will be multiplied by 8/10 before being included in the course grade computation.) The first checkoff is worth 1 point, while the other two are each worth 4.5 points. Readability includes comments, indenting, sequence of procedures in your file, appropriate use of Scheme (e.g. by avoiding the use of sentence/word procedures with lists), and choice of names for procedures and their placeholders. Some readability guidelines: Procedures that deal with the same kind of structures should be together in your file, so that they are easy to find. Rather than using a cond with a zillion conditions, you should probably use assoc with a table or list-ref with a list. Use procedures for side effects only where necessary (e.g. to do output). Your comments at the start of the program should include an overview of how all your procedures fit together. Each nontrivial procedure should be accompanied by a description of the procedure's purpose, a sample call, and the types and expected values for its arguments. Appropriate test cases are described in each project writeup. Use the testing framework as in the miniprojects to test your component procedures in isolation, to provide more evidence that they will work together correctly. Students in the past have attempted to fake their tests. This is not all that difficult to catch, since you are submitting your program solutions; the penalty will be a 0 on the project. To avoid looking like you faked your tests, be sure to rerun your tests after you make any final changes to your code.

Working in a partnership

With either short problems or a project, you may work in a partnership of two. We encourage project partnerships. If you work in partnership on the short problems, make sure that both partners are involved in the design, coding, and testing of each solution. A partnership should turn in only one project solution or only one set of short problem solutions (with both your names and logins in all relevant files). A partnership should also supply a file named partners.readme that describes the following:

how you split the work between partners, and how, if you were given 10 extra points to split between you, you would distribute these points between you and your partner. (Both partners will receive the same project grade.)

There will be no difference in how we assign grades between projects that were worked on by a partnership versus those worked on singly. They will be treated the same.

One final concern

Turning in unacknowledged code not written by members of your partnership or supplied by us constitutes cheating. It will be penalized by a grade of F in CS 3L and referral to the Office of Student Conduct. We value the benefits you get from working on a large project and in a partnership —please take this seriously and do the work honestly. 29.2 Blocks World(1 step) 29.2.1 (Display page) Blocks World project details CS 3 "Blocks World" project

Background

Robotics is a leading research area in computer science. A program that controls a robot must represent the environment somehow, and be able to sense changes and update its internal representation accordingly. It must also be able to plan actions of the robot and anticipate possible consequences of those actions. Robots are often programmed to act autonomously; some, however, are guided through a user interface that may involve complicated language processing. This project is intended to give you a small taste of some of the programming techniques needed to guide a robot.

Project overview

In this project, you complete a program that manipulates stacks of blocks (all the same size) in a two- dimensional environment. In Scheme, the environment is represented by a list of stacks. A stack is represented by a list of blocks, which may be empty; the first block in the stack is the top block, which rests upon the second block, and so on; the last block in the stack rests on the table. A block is represented by a two-word sentence. The first element is the block's id number; no two blocks in the environment have the same id. The second element is the block's color. (The display system provides eight colors: black, blue , green, cyan, red, magenta, yellow, and white. Cyan is blue-green. Black blocks won't show up on the display very well.) An example appears below.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 89 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

picture of environment Scheme representation

(((1 red) (2 cyan)) () ((4 red) (3 green)))

The program will read and execute commands that move blocks in the environment or request information about the environment. There are three kinds of commands: (quit) The quit command writes the current blocks environment to a file named blocks.out, and terminates the program. (put block-description1 on block-description2 ) The put command clears the tops of two blocks, then moves the first block onto the second. (what is preposition block-description ) The what is command is a question about the environment. ("On" and "under" are the prepositions that are legal in this command.) (add block-description) The add command randomly adds a new block to an existing stack in the environment. Note, the block description in this command is a subset of the block description in other commands. (remove block- description) The remove command with the above format will remove a single block, clearing blocks off the top of the target block as necessary. (remove number multiple-block-description) The remove command, when followed by a number 2 or greater, should remove number blocks matching multiple-block-description from the environment. Blocks are not described by their ids, but may be described by their colors. Each block description is one of the following: "a block", "it", "a color block", or "the color block", except in the add command, where it is one of "a block" or "a color block". A multiple block description (only used in the remove n command) is one of the following: "color blocks" or "blocks". Block descriptions have different meanings in the different commands.

Block descriptions in the "put" command

In the put command, each block description must refer to exactly one block. For a block description that starts with "the", the environment is searched for blocks that qualify. If there is exactly one such block, that's the one that's referred to; otherwise, the program should print an error message and ignore the command. In the sample environment given previously, "the cyan block" refers to block #2; "the red block" is ambiguous and "the yellow block" is nonsense. For a block description that starts with "a", the environment is similarly searched for blocks that qualify. If there are one or more, one of the blocks that qualify is chosen randomly but in such a way that the block isn't moved on top of itself; otherwise, the program should print an error message and ignore the command. That means, for instance, that the command

(put a block on a block)

should always be legal in an environment with two or more blocks. The block description "it" is described below.

Block descriptions in the "what is" command

In the what is command, a block description that starts with "the" is handled as in the put command. Thus the response to

(what is on the cyan block)

should be

(1 red)

while the response to

(what is on the red block)

should be the error message

(more than one red block exist)

A block description that starts with "a" may refer to more than one block. For such a description, the response should include all the relevant blocks. For example, the response to

(what is under a red block)

should be

(2 cyan) (3 green)

It may happen that no blocks are on or under the specified block(s). The appropriate response is "nothing". For example, the question

(what is under a green block)

produces the response

(nothing)

Block descriptions in the "add" command

In the add command, a block description can only come in the form "a block" or "a color block". Descriptions starting with "the" or consisting of "it" should generate errors. Legal block descriptions to the add command are handled the same way as in the corresponding descriptions in put and what is commands. As a result, a call to add should create a new block. The block should have a unique id -- that is, a positive integer different than any of the ids of the other blocks in the environment. When the block description is "a block" and a random color should be chosen from the possible colors. The location of the block should be in a randomly chosen stack, placing the block on the top of any existing blocks in the stack. If your environment is empty, with no stacks, you should create an empty stack and add the new block to it. For example, the command

(add a green block)

given in the environment (((1 green) (2 blue)) ((4 white))) can result in the following environments:

(((3 green) (1 green) (2 blue)) ((4 white)))

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 90 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

or

(((1 green) (2 blue)) ((3 green) (4 white)))

Note, the "id" of the added block need not be 3, but cannot be 1, 2, or 4.

Block descriptions in the "remove" (a single block) command

Block-description should be checked in the same manner as put command: the description should refer to a single block. The target block should be removed from the from the environment.

Block descriptions in the "remove" (multiple blocks) command

The remove number command takes a multiple block-description, which is one of "blocks" or "color blocks". If there are not number blocks that satisfy the description in the environment, the command should return

(there are fewer than number color blocks)

or

(there are fewer than number blocks)

if a color was specified or not.

What is "it"?

"It" essentially means the block most recently mentioned or asked about. If this cannot be determined unambiguously, the program should print an error message and ignore the command. In the command following a successfully executed put command, "it" refers to the block moved. In the command following a successfully executed question, "it" refers to the answer. If there are more than one block in the answer, "it" is ambiguous in the following command. "It" is undefined in the command following a command that produced an error message.

Example

Given below is a sample dialog that illustrate how the program should behave. It starts with the environment given on the previous page. resulting command environment notes or response (put the Block #1 was moved to the table to clear the top cyan block of block #2. Then block #2 could be moved atop on a red block) either of the red blocks.

(put it on "It" means block #2 here. That block didn't need to the green block) be cleared, but block #3 did.

(put it on (more than one the red red block "It" still means block #2. block) exist) (put it on (please explain a red what is meant "It" was forgotten because of the error message. block) by "it") (put the cyan block (no yellow on a yellow block exists) block) (put a cyan (the cyan block Putting a red block on a red block would work; one block on a cannot be moved of the red blocks would be randomly chosen and cyan block) onto itself) moved atop the other one. (what is on a red (nothing) block) (put it on (please explain "It" is undefined here since nothing satisfied the a cyan what is meant block) by "it") preceding question. (what is under the (3 green) cyan block)

(put it on "It" is now block #3. Block #2 is moved to the table a red to clear block #3, and then one of the red blocks is block) randomly chosen for the destination. (put the cyan block on the green block) (what is on (3 green) (2 The blocks could be listed in the opposite order. a block) cyan) (please explain (what is The previous question was answered with two what is meant under it) by "it") blocks, so "it" is ambiguous. (what is on (no yellow a yellow An error message resulted instead of "nothing". block exists) block) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 91 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(put the A clever program would notice that the cyan block cyan block is already on the green block. Straightforward on the green processing, however, would first move block #2 to block) the table, then move it back on block #3.

"It" is now the cyan block. Choosing the other red (put a red block, block #1, would have required moving block on it) blocks #2 and #3 to the table before moving block #1 atop block #2.

(remove a We find block #3, clear everything on top of it, and green block) then remove it.

Any block could have been added, but we (add a randomly generated block #5 and placed it on the block) third stack.

(remove 2 block #1 and block #4 are removed. red blocks)

(there are (remove 3 There are only 2 blocks in the environment, so fewer than 3 blocks) blocks) removing 3 is impossible.

Code you are to provide

A framework for this program appears here and in the file ~cs3/public_html/programs/blocks.fw.scm. It includes calls to two procedures that you are to write. 1. analyzed

Given a command submitted by the user, a blocks environment, and the current value of "it" as arguments, analyzed returns the result of translating the command to a form that's easier to handle and resolving references to "the ... block", "a ... block", and "it". If these references cannot be resolved successfully, analyzed returns #f.

A put command should be translated to a three-element list whose first element is the word put and whose second and third elements are blocks. A what is command should be translated into a list of at least two elements whose first element is either under or on and whose remaining elements are blocks. A add command should be translated into a list of two elements whose first element is the word add and whose second element is a block. Either remove command should be translated into a list of at least two elements, whose first element is the word remove and whose remaining elements are blocks.

Analyzed is also where you should display error messages. Analyzed won't return an error message; rather, when there is an error, it will return #f. Within the body of the procedure, use the show function to display the appropriate error message. command possible analyzed results (put the cyan block on a red (put (2 cyan) (1 red)) block) (put (2 cyan) (4 red)) (put it on the green block) (put (2 cyan) (3 green)) (put it on the red block) #f (put it on a red block) #f (put the cyan block on a yellow #f block) (put a cyan block on a cyan #f block) (on (1 red) (4 red)) (what is on a red block) (on (4 red) (1 red)) (put it on a cyan block) #f (what is under the cyan block) (under (2 cyan)) (put (3 green) (1 red)) (put it on a red block) (put (3 green) (4 red)) (put the cyan block on the (put (2 cyan) (3 green)) green block) (on (1 red) (2 cyan) (3 green) (what is on a block) (4 red)) (The four blocks may appear in any sequence in the list.) (what is under it) #f (what is on a yellow block) #f (put the cyan block on the (put (2 cyan) (3 green)) green block) http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 92 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(add a green block) (add (5 green)) (remove it) (remove (5 green)) (add a block) (add (6 magenta)) (remove a magenta block) (remove (6 magenta)) (remove 2 blocks) (remove (2 cyan) (3 green)) (remove 2 red blocks) (remove (1 red) (4 red))

2. execute

Given an analyzed command, a blocks environment, and the current value of "it", execute executes the command by moving relevant blocks or answering the specified question. Execute then calls handle-cmds with the updated blocks environment and "it" values.

3. resolved-descr

Your code should include a procedure named resolved-descr (short for "resolved description"). Resolved-descr will take three arguments: a block description such as (a red block) , a blocks environment, and the value of "it". It will return a list of the blocks in the environment that satisfy the description. Thus

(resolved-descr '(a red block) '(((1 red) (2 cyan)) () ((4 red) (3 green))) '( ) )

should return

((1 red) (4 red))

Miscellaneous requirements

In the what is command, "under" means "directly under" and "on" means "directly on". Thus in the environment

(((1 red) (2 green) (3 blue)))

the command

(what is under the red block)

should only list (2 green) , not (3 blue) . Similarly, the command

(what is on the blue block)

should list only the green block, not the red block. The two versions of the what is command—"what is on ..." and "what is under ..."—have almost identical behavior. You should minimize the amount of duplicate code you use to implement these two types of command. In both the analyzed and the execute procedures (and in your helper procedures), "it" is to be represented as a list of blocks. An undefined "it" is represented by the empty list; an ambiguous "it" corresponds to a list that contains more than one block. In the situation where a block is to be moved to an empty stack and the environment doesn't contain any empty stacks, an empty stack should be added to the end of the list and the block moved there. For example, moving block #2 to the table in the environment

(((1 red)) ((2 green) (3 blue)))

(which consists of a stack containing one red block and a stack containing a green block and a blue block) should produce the environment

(((1 red)) ((3 blue)) ((2 green)))

Don't rearrange the stacks while moving. Your program should simulate a robot that moves single blocks from stack to stack; it shouldn't move entire stacks at once. You may assume that the environment read from the file is a legal and reasonable one. That is, it's a list of stacks, each of which is a list of blocks, with each block having a unique id number and a legal color, and there are at least two blocks in the environment. You may also assume that user commands are formatted correctly as described on the previous page. The errors you must detect are the following:

referring to "the" block when there aren't any, or more than one;

trying to move a block on top of itself;

referring to "it" when it's not defined, or is ambiguous.

Any error message not involving "it" must name the color of the relevant block(s). Don't change the framework code we provide. We will be testing analyzed, execute, and resolved-descr in isolation so they need to return values in a format exactly like the examples above. Put your completed program in a file named blocks.scm in a directory named project. In a file named blocks.tests , include tests that exercise your program completely. (Also provide the file partners.readme if you're working in partnership.) Provide example runs in which all the commands, block specifications, and error conditions appear. The example dialog on the previous page is a good start. You should also include commands such as

(put a red block on a red block)

and

(put it on a red block)

with environments that contain two red blocks and a red block identified as "it". Test your procedures individually as well as in combination, and include the results of these tests in your blocks.tests file.

Suggested approach

One possible approach to this project would be to design and test the blocks movement procedures first. (Our solution uses three: one to clear a block, another to move a block to the table, and a third to move one block on top of another.) Since these procedures only involve blocks environments—actually, they only involve lists of sentences—they will be easy to test in isolation. Another approach is to focus on the command analysis first. The put command can be implemented separately from what is; the resolved-descr procedure, as mentioned above, will be useful for both. http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 93 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

29.3 Connect4(1 step) 29.3.1 (Display page) Connect4 project details CS3 Project: Connect Four

In this project, you will finish a program that plays the game Connect Four. You will need to understand the framework code, come up with a storage structure for the board, write some "smarts" for the computer player, and implement a "bomb" piece.

Background

The game Connect Four involves dropping pieces into a board that is seven spaces wide by six spaces high (making 7 columns by 6 rows). Two players alternate turns and the first to place four pieces in a row (either horizontally, vertically, or diagonally) wins. The board is held vertically, and a player only chooses which column to place a piece; the piece will fall to the lowest unoccupied row. Connect Four is a very old game, although the name comes from a board game released by Milton Bradley. There are many on-line versions of Connect Four available, and it will be especially valuable for you to familiarize yourself with it through playing games. As it turns out, the game has recently been "solved", and a computer can be programmed to play perfectly (you are not being asked to program a perfect solution, however!). The wikipedia entry (at http://www.wikipedia.org/Connect_Four) has a bit more information (much has been deleted recently, it seems), while the wikibooks entry may have too much. One version can be played here. While the standard version of Connect Four involves two players on a 7x6 board, the program you write will be able to handle any number of players and any (reasonably) sized board.

Framework code

The framework code, available here, is able to play on a board that is only one row high right now. Additionally, any computer player is quite stupid, choosing randomly when placing a piece, and the game doesn't correctly end when four pieces are placed in a row. It also has some bugs, like accepting moves that are outside the width of the board. The framework code contains several distinct groups of procedures:

1. Code to represent a "player" with a name, a piece color, and a way to choose a next move for that player. Constructors and selectors for a player are included. (You need to add some code here.) 2. Code to represent a "board". (You will be changing this.) 3. Code to play the game and take turns. 4. Code to represent moves, which in most cases is a 0-based column index. That is, the move 0 means the piece is to placed in the left-most column. Also in this section are procedures to get next moves for humans and computer players. (You'll need to change the code that figures out the computer's next move.) 5. Graphics routines, divided into a few straightforward procedures and a bunch of ugly ones you can safely ignore. (You will need to change one of the straightforward procedures.)

The first thing you should do is spend some time investigating how these procedures work together, playing the one-row-high game and testing out individual procedures. Understanding the existing code will help you complete the tasks below.

Problem

There are three tasks that you need to complete. 1) Represent a two-dimensional board.

In the framework code, a board is represented by "association lists" of column and piece color. In this scheme, there is no way to keep track of the row in which a piece sits. You will need to choose a way to store which pieces are currently in a two- dimensional board of any (reasonable) size. You probably don't want to use the association list strategy that was used in the framework code. You will need to change all of the procedures that are in the "board" section of the code,

new-board: the constructor, returns an empty board for a new game possible-move?: returns #t or #f depending on whether the player can make the move. add-piece: returns an updated-board after a player has made a certain move winner?: a predicate that determines whether the last move created a winning position for a player

as well as the procedure

draw-pieces: goes through each piece on the board and calls the graphics routine draw-piece. This is in the section titled "drawing the board", near the end of the framework code.

Any representation you come up with that can correctly implement these five procedures is fine for the purposes of this project. This is the whole point of data abstraction! Be sure not to change the arguments that the procedures take or the type of return value that they provide: this is also an important part of data abstraction. (For instance, don't change how a move is represented, or which arguments add-piece takes). There are several different strategies you can use in task 1, and your choice will make some of the five procedures easier (or more difficult) to write. Remember, any solution you implement will have to work with variable sized boards. Make sure to test things out by changing *board-width* and *board-height* (using define) and starting a new-game without restarting STk.

2) Make the computer play smarter

In the end of the section titled "moves", the procedure get-computer-move takes a board and a computer player and decides what the computer should do. To this end, it first determines if there are any moves that the computer can make. If there is at least one, it chooses the best one, prints out its choice, and returns that best move. In the framework code, the computer chooses randomly from all the possible (non-bomb) moves that it can make. You need to fix things so that: http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 94 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

the computer will win if it can on its next move; the computer will choose a move, when it can, that blocks another player from getting 4-in-a-row on the next move; the computer will make a random yet valid move if it can't win or block. (When the board is full, the only valid move is to quit.)

Remember, your solutions need to work for games with more than two players. This will be particularly important to consider for the second point above. (If more than one opponent can win when the computer has to decide where to place its piece, you can block any of them.) With your additions the computer will still be pretty stupid and, hopefully, easy to beat. If you want to implement more strategies, by all means feel free to do so:

If the computer can't win or block, have it choose a piece towards the middle of the board rather than the edges (if the middle column isn't too high). If the computer can't win, have the computer choose bomb pieces some of the time (see below). Or, have it choose bomb pieces at good times. Don't let the other player complete three in a row with open ends on either side, especially on the bottom row! etc.

You'll need to be familiar with how a "move" is represented in the code. A move can be one of three things:

1. a number that indicates the column to place a "normal" piece. This is 0-based, so 0 represents the left-most column. 2. a word starting with "b" and ending in a number (as above). This indicates a move to place a bomb piece. 3. #f, meaning there were no moves left to make or the player decided to quit.

3) Add "bomb" pieces

To make things more fun, you'll add functionality to allow players to place a certain number of "bomb" pieces during the game. A bomb piece should remove pieces in a 3x3 box centered on the space where it detonates. The bomb should detonate in the same cell as the topmost piece in the column it has been placed. (Note, the bomb will never remove a piece from the space above where it detonates, so it can remove at most 8 pieces). If, after removing the pieces in nearby columns, any still-remaining pieces are suspended they will need to drop into the lowest unoccupied space in that column. Bombs that are dropped on columns at the edges of the board will only affect two, rather than three, columns. It isn't clear how this will change the strategy of the game (we have no idea!), so after you get this and task 1 above working, you might play some human versus human games and see how things play out. If you want to change the default number of bombs available, or change the amount of damage a bomb does, feel free to do so. A few details:

To implement this, you will need to change the add-piece procedure from task 1 to correctly handle bomb moves. After a bomb is played by a certain player, a different player may have 4-in-a- row. With the arguments to winner?, however, it is difficult to test this. You may assume that a player can only win on his/her/its turn. When the other player's turn comes around, he/she/it can win at that point. If a bomb is dropped on a full column, it should detonate on the topmost piece. If a bomb is dropped in an empty column, it should fail to detonate at all (that still counts as a turn). Certain representations for a board will make it easy to have suspended pieces drop; other representations will make things more difficult. Overall, however, this part of the task shouldn't be particularly difficult. (Some students have initially thought that this would be the hardest subtask in the whole project!) We have some cool bomb animations you can use if you want (this is optional). In order to do so, you need to call the procedure draw-bomb with a column and row number when you want the animation to take place—presumably, sometime after you have figured out that somebody made a valid bomb move. You can see the draw-bomb procedure near where the draw-pieces procedure is defined. You should copy the three bomb picture files—bomb_s.gif, bomb_m.gif, and bomb_l.gif, available here—into the same directory as your code. You'll notice that the framework code complains if it can't find these files. Make sure to start up emacs in the same directory as you have stored the files, or it may not find them!

Suggested approach and tips

Certainly, you want to implement task 1 first, and get the basic game working for two dimensional boards. You should have this working, or close to working, for checkoff #2. The winner? procedure is likely to be the most challenging part of task #1. As there are several different approaches you could go with, take time to plan, debate with your partner, and consult with your TA before you start. You can play a bomb-free game (human versus human as well as human versus computer) as soon as you finish task 1—even before you finish winner?, really. Definitely do this, to help you get a feel for the code as a whole. As you start to implement task 2, you may find that you want to change the board representation, or at the very least add more accessor procedures. Computer programming is an iterative process, and going back to improve one part of your code to make other parts easier to write is usually the right thing to do! The strategy used in tic-tac-toe should prove useful, in part. You should probably write a procedure opponents, which returns a list of the other players in the game. And, you will certainly make use of the winner? procedure you wrote for task #1! While you have things partially developed and are testing things, you may find that the graphics stop working properly. Usually new-game will fix things (by calling initialize-graphics), but you may need to quit and restart STk. It is particularly important, in task 1, for you to make an effort to implement add-piece correctly. We will use it to test your solution to task 1. 29.4 Yukon(1 step) 29.4.1 (Display page) Yukon project details

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 95 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

CS 3 project choice 3 Yukon solitaire

Background

The solitaire game of Yukon is played as follows. First, the deck of 52 cards is dealed into seven stacks as shown in the diagram below. This is called the tableau. The leftmost stack contains one card, face up. The next stack contains one face-down card, with five face-up cards on it, arranged so their suits and ranks are visible. The third stack contains two face-down cards and five face-up cards; the fourth stack contains three face-down cards and five face-up cards; and so on. D D D D D D "U" means face up, D D D D "D" means face down. D D D D D The physical top of each stack is listed at the bottom of the D D D D D D corresponding column of cards in the diagram. U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U

There are also four foundation stacks, one for each suit, that are initially empty. These are generally placed above the tableau. There are two kinds of moves:

Moves from tableau to foundation The top card of any tableau stack is eligible to be moved to a foundation stack. An ace is the only card that may be moved to an empty foundation stack. Foundation stacks are built up in order, one stack for each suit, so a 2♥ may be placed atop the A♥, the 3♥ on the 2♥, and so on. Moves from one tableau stack to another Any face-up card in the tableau, together with the cards on top of it, may be moved onto a card of the opposite color and next lower rank that's at the top of a tableau stack. A king, also together with the cards on top of it, is the only card that can be moved to an empty tableau stack. When a face-down card is exposed by such a move, it is turned face up.

The game is won when all 52 cards are moved to the foundation. More details are available on the web (Google "yukon solitaire" for information). Here is a segment from an actual game. Tableau (stack top is the bottom card in each column) — — — — — — "—" means a face-down card. — — — — Possible moves from one tableau stack to another: 6♥ — — — — — to 7♣, 2♥ to 3♠, 4♠ to 5♥, 9♣ to 10♦, 2♠ to 3♥, 2♦ to 3♠, — — — — — — 4♣ to 5♥. When a card moves, all cards atop it on the 7♣ Q♠ 6♥ K♣ A♥ 9♦ J♥ tableau stack also move. A♦ 2♥ 10♠ A♠ 7♦ 4♦ 6♣ K♠ A♣ 9♣ 3♦ 8♣ No moves may be made from the tableau to a 8♦ 3♣ 4♠ 2♠ 2♦ 4♣ foundation stack. 7♥ 3♥ 10♦ Q♦ 5♥ 3♠ We choose to move the 9♣ (along with the 2♠ and Q♦) to the 10♦. This frees up the A♠, which we move to a foundation stack, and the A♥, which we also move. Finally, we turn up the exposed face- down card formerly under the A♥. Here's the result. Foundation A♠ A♥ Tableau (stack top is the bottom card in each column) — — — — — — — — — — Possible moves from one tableau stack to another: 6♥ — — — — — to 7♣, 2♥ to 3♠, 4♠ to 5♥, 2♠ to 3♥, 2♦ to 3♠, J♥ to Q♣, — — — — — — 4♣ to 5♥. 7♣ Q♠ 6♥ K♣ Q♣ 9♦ J♥ A♦ 2♥ 10♠ 7♦ 4♦ No moves may be made from the tableau to a 6♣ K♠ A♣ 3♦ 8♣ foundation stack (the 2♥ and 2♠ would have to be on 8♦ 3♣ 4♠ 2♦ 4♣ top of a stack to be eligible to move to a foundation). 7♥ 3♥ 10♦ 5♥ 3♠ 9♣ 2♠ Q♦ Now we choose to move the J♥ atop the Q♣. Again, the cards on top of the J♥ get moved also. This exposes a face-down card, which we turn up. We then move the 6♥ and the cards on top of it to the 7♣. This also exposes a face-down card. Here's the result. Foundation A♠ A♥ Tableau (stack top is the bottom card in each column) — — Possible moves from one tableau stack to another: 2♥ — — — to 3♠, 8♦ to 9♠, 4♠ to 5♥, 9♣ to 10♥, 2♠ to 3♥, 4♣ to http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 96 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

— — — to 3♠, 8♦ to 9♠, 4♠ to 5♥, 9♣ to 10♥, 2♠ to 3♥, 4♣ to — — — — 5♥, 2♦ to 3♠, 9♠ to 10♥. — — — — — — — — — — 7♣ Q♠ 10♥ K♣ Q♣ 9♦ 9♠ 6♥ A♦ 10♠ J♥ 7♦ 2♥ 6♣ A♣ 4♦ 3♦ K♠ 8♦ 4♠ 8♣ 2♦ 3♣ 7♥ 10♦ 4♣ 5♥ 3♥ 9♣ 3♠ 2♠ Q♦ After a few more moves, the game appears as follows. Foundation A♠ A♥ A♣ Tableau (stack top is the bottom card in each column) — — — — — — — — — Possible moves from one tableau stack to another: — — — — — A♦ to 2♠, 8♦ to 9♠, 5♠ to either red 6, 3♥ to 4♠, 2♠ to 7♣ Q♠ 5♠ K♣ Q♣ J♣ 6♦ 3♥. 6♥ A♦ 4♦ Q♦ J♥ 10♦ 6♣ 8♣ J♠ 10♠ 9♣ The 2♠ may also move to the foundation ♠ pile. 8♦ 4♣ 10♥ 9♦ 2♠ 7♥ 3♠ 9♠ 7♦ 2♥ 3♦ K♠ 2♦ 3♣ 5♥ 3♥ 4♠ First we move the 2♠ to the A♠ in the foundation. Then we move the 5♠ to the 6♥, creating an empty stack to which any K may be moved. We move the K♣ to expose a face-down card. Here's the board that results. Foundation (only the top card in each stack is shown) 2♠ A♥ A♣ Tableau (stack top is the bottom card in each column) — Possible moves from one tableau stack to another: 5♠ — — — to 6♦, 4♣ to 5♦, 3♥ to 4♠, 8♦ to either black 9, 4♠ to — — — — 5♦. — — — — — 7♣ Q♠ K♣ 5♦ Q♣ J♣ 6♦ 6♥ A♦ Q♦ J♥ 10♦ 5♠ 6♣ J♠ 10♠ 9♣ 4♦ 8♦ 10♥ 9♦ 8♣ 7♥ 9♠ 7♦ 4♣ 3♦ 3♠ 2♦ 2♥ 5♥ K♠ 4♠ 3♣ 3♥ We went on to lose this game. Yukon isn't all that hard to win. One book, The Complete Book of Solitaire and Patience Games, by A.H. Morehead and G. Mott-Smith, estimates the odds of winning as 1 in 4. One former CS3 instructor claims to have done somewhat better, winning around 42% of the time.

Problem

You are to complete a program to play Yukon solitaire. A framework for this program appears here and in the file ~cs3/public_html/programs/yukon.fw.scm. It specifies the representation of a board—you don't get to change this—and provides relevant access procedures:

foundations, which returns a list of the four foundation stacks; tableau, which returns a list of tableau stacks; face-up, which returns the list of face-up cards in the given stack with the top of the stack first in the list; and face-down, which returns the list of face-down cards in the given stack.

It also provides various procedures for shuffling a deck of cards, building the initial board, and printing the board. It includes calls to several procedures that you are to write:

possible-moves, which should return a list of all possible moves one can make with the given board. You may choose the representation of a move; however, the comments in your code should clearly document how a move is represented. The version of possible-moves supplied in the framework always returns an empty list. choice-from, which chooses a move from among those in a given list of moves. The version of choice-from provided in the framework code merely presents a list of moves to the user and asks for a selection. You should improve this in one of the following ways: completely error-check the user's input to ensure that it will not cause the program to http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 97 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

crash, and continue to ask for a selection as long as the user responds with nonsense; or highlight obviously useful moves, for example, those that allow a face-down card to be exposed. (You don't need to do both.) updated, which returns the result of making the chosen move on the given board. The version of updated supplied in the framework returns the board unchanged.

Finally, the framework code includes an incomplete test for a win that uses the true-for-all? procedure you wrote in an earlier lab activity.

Miscellaneous requirements and suggestions

You are not to change the representation of a board or any of the framework code except for the three procedures possible-moves, choice-from, and updated described above. Respect the data abstractions set up for boards and cards by using the access procedures provided. (You will need to provide extra board operations to implement the updated procedure.) Your code should not include complicated cond expressions that rely heavily on there being only four foundation stacks or only seven tableau stacks. Use recursion or higher-order procedures to code more general (and shorter) procedures. Put your completed program in a file named yukon.scm in a directory named project. In a file named yukon.tests, include tests that exercise your program completely. (Also provide the file partners.readme if you're working in partnership.) In particular, one of your tests should include a winning game. Test your procedures individually as well as in combination, and include the results of these tests in your yukon.tests file. This project breaks down naturally into two big pieces—the generation of moves and the updating of the board—plus the improved choice-from. In our solution, each of these was a couple of pages of code. Each big piece is a candidate for the second or third checkoff. A procedure that's not required but is likely to prove useful for debugging your updated procedure is a board consistency checker. 29.5 Short problems(4 steps) 29.5.1 (Display page) Short problem details Short problems

There are three groups of short problems. For submission, turn in a solution to one from each group. Submit your solutions (collectively) as "short-problems". If you work in a partnership, include the names and logins of both partners in the files you submit, and provide a readme file in which you describe the work of each partner. Use the testing framework from earlier miniprojects to generate test output. 29.5.2 (Display page) Short problems, group A Group A: Recursion Practice (do one problem from this group)

A1: Bowling Scores

Background

The game of bowling is played by rolling a ball down a bowling lane to knock down the pins at the end of the lane. The situation is diagrammed in the figure below.

A bowling game is divided into ten frames. The bowler is allowed up to two balls in each frame to knock down all ten pins. Knocking down all the pins with the first ball ends the frame, and is called a strike. Knocking down all the pins with the first two balls is called a spare. Knocking down fewer than ten pins with the first two balls is called a miss. A bowler earns one point for each pin knocked down, plus bonuses for each strike and spare. A strike scores 10 points plus the total of the next two balls; a spare scores 10 points plus the score of the next ball. A strike in the tenth frame earns the bowler two extra balls; a spare in the tenth frame earns one extra ball. Extra balls earned by a strike or spare in the tenth frame do not earn bonus points. An example of how a game is scored is shown below. frame balls score for the frame cumulative score 1 9+1 (spare) 10+0=10 10 2 0+10 (spare) 10+10=20 30 3 10 (strike) 10+10+6=26 56 4 10 (strike) 10+6+2=18 74 5 6+2 8 82 6 7+3 (spare) 10+8=18 100 7 8+2 (spare) 10+10=20 120 8 10 (strike) 10+9+0=19 139 9 9+0 9 148 10 10 (strike) + 10+8 (bonuses) 10+10+8=28 176 Bowlers use a score sheet that's organized to clearly display the score for each frame and each ball. Here's how the game just described would be scored:

In olden days bowlers kept their own scores. Embedded computers, however, have brought automatic scorekeeping to bowling.

Problem

Write a procedure named game-score whose argument is a sentence of integers corresponding to the balls rolled in a single bowling game. Game-score should return the total score for the game. Assume that the game is legal and complete; i.e. appropriate values are provided for all balls rolled, and for no extra balls. The game described on the previous page would be represented by the call

(game-score '(9 1 0 10 10 10 6 2 7 3 8 2 10 9 0 10 10 8))

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 98 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Miscellaneous requirements

If you use helper procedures, test them in isolation as well as with game-score. Include a comment with each of your procedures that describes its arguments and return values as specifically as possible. At least one of your procedures will be recursive. Avoid unncessarily long or complex case analysis. Use reasonable names for procedures and place holders. Test game-score on at least the following:

a game that includes three consecutive strikes; a game that includes two consecutive strikes, followed by a nonstrike; a game that includes a strike followed by a spare; a game that includes a spare followed by a strike; a game that includes a spare not followed by a strike; a game that includes two consecutive frames that aren't strikes or spares; a game with a strike as the first ball of the last frame; a game with a spare in the last frame; a game with two strikes in the last frame.

You may use as many test games as you want, but you need no more than three games to test all these possibilities. If you want some help scoring a game, you can check out this or this other bowling score calculator. Save your code and test cases in a file called bowling.scm in the short-problems directory.

A2: The "Doctor" Program

Background

The Doctor program (originally called "Eliza") was written in the early 60's by Joseph Weizenbaum of MIT. It simulates a Rogerian psychologist, in that it merely responds noncommittally to anything typed by the user. The program is a relatively simple one. It doesn't try to analyze the grammar of the user's input. It does try, however, to put enough content into the response to make sense. Weizenbaum's idea was to show that it didn't take much intelligence or programming pizzazz for a program to act "intelligent". Here are some of Doctor's tricks.

a. It never gives only a fixed response in a given situation; it chooses randomly from a group of responses like "oh, that's nice", "please go on", "please continue", "many people have the same sorts of feelings", etc. Some of these are concatenated to a version of the input: a reply to the comment "i am a loser" might be "why do you think you are a loser?" or "you feel that you are a loser". It correctly translates "I" and "me" to "you" in these situations, but sometimes has trouble going from second person to first person (i.e. translating "you" to "I" or "me"). 2. Doctor also has a set of "trigger words" and responses to input containing those words. To a sentence mentioning one of the words "depressed", "depression", "depress", or "suicidal", it might respond "depression can be treated, you know" or "if you ever feel depressed, try drinking a glass of warm milk". It knows about certain vulgar terms, and can respond with "please watch your language" or "same to you, fella". Some of the responses will actually mention the trigger word, by having slots that get filled with the word that triggered that sentence; mentioning a family member, for instance, might result in the sentence "tell me more about your ___", with the particular family member (mother, father, etc.) being substituted in the blank. 3. Doctor keeps a history of the patient's remarks, and can respond if appropriate with comments like "earlier you said ...", "you do not seem very talkative today" (in response to several short answers), or "you seem to have a very negative attitude" (in response to several answers with the word "not" or "no").

Problem

The code for a (rather simple-minded) Doctor program is available here. You are to improve it by adding some of the features just mentioned:

both features mentioned in (a), that is, a response derived from the sentence typed by the user, and a response chosen randomly from a group of canned responses; response to mention of a family member as described in (b), plus response chosen randomly for some other set of trigger words (you may choose which ones); one of the features mentioned in (c), that is, some response that examines the history of sentences typed by the user.

You should check the patient's history before you check for trigger words, and generate the responses mentioned in (a) above as a last resort. The code we give you is not completely written in the functional paradigm, since reading and printing are essentially procedural activities. The code you add to it, however, should be completely functional; none of your code should compute a value that isn't returned, or have any side effects. (That is, you shouldn't add code that uses the procedures described in chapter 20.) Along with a solution program, prepare a sequence of user inputs that demonstrate all capabilities of your program. You will lose points for an incomplete demonstration. Your inputs should not only display all five types of response described above, but should also provide evidence that your program is generating responses with the proper priority (i.e. checking history before trigger words, and checking trigger words before generating a random response). Put your solution program into a file named doctor.scm and your tests in a file named doctor.tests in your short-problems directory.

Useful Scheme procedures

The random and list-ref procedures will come in handy. Random takes a single argument n, and returns a random integer between 0 and n-1, inclusive. The list-ref procedure acts like item except that its numbering starts at 0. One may combine these in a procedure choose, and use it to return a response to vulgarity:

(define (choose L) (list-ref L (random (count L))) )

(choose '((same to you fella) (please watch your language) (you really feel strongly about this dont you) ) ) In the example, punctuation was omitted to avoid conflicts with Scheme operators. A perhaps better solution is to use strings. You may choose either approach.

A3: Caesar Ciphers

Background

A Caesar cipher of index k is an encoding that results from replacing each letter in a text segment by the letter that is k places after it in the alphabet. The encoding "wraps around"; thus the letter 1 place after Z is A. For example, the Caesar cipher of index 4 would replace A by E, B by F, ..., V by Z, W by A, and so on.

Part 1

Write a set of Scheme procedures that encodes text with a Caesar cipher. Your top-level Scheme procedure should be named encode. It should take two arguments, an integer k and a list representing text to encode; it should return a list representing the encoded text. In the text list, letters are represented by the corresponding atoms; punctuation is represented by the symbols PERIOD, COMMA, SPACE, and so on. (Note that STk converts all input to lower-case automatically.) Here are some examples. call to Scheme encode procedure returned value (encode 5 (S T B SPACE N X SPACE Y M J SPACE Y N R J COMMA '(n o w SPACE i s SPACE t h e SPACE t i m e COMMA SPACE K T W SPACE F Q Q SPACE L T T I SPACE K T Q P PERIOD) SPACE f o r SPACE a l l SPACE g o o d SPACE f o l k PERIOD))

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 99 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

Part 2

Write a set of Scheme procedures that decode text that was encoded with a Caesar cipher. The top-level Scheme procedure should be called decode. It will take a single argument representing the encoded text. Using a statistic called "chi squared", your program will predict which Caesar cipher was used to encode the text. The chi squared statistic is computed as follows:

χ2 = sum over all letters of (observed frequency – expected frequency)2/ (expected frequency)

Expected frequencies of letters in English text appear below. letter frequency letter frequency letter frequency letter frequency A 0.07666 H 0.04191 O 0.07440 V 0.00859 B 0.01837 I 0.07371 P 0.02482 W 0.01224 C 0.03664 J 0.00125 Q 0.00343 X 0.00889 D 0.03788 K 0.00486 R 0.06745 Y 0.01523 E 0.12016 L 0.04089 S 0.06208 Z 0.00306 F 0.02275 M 0.02783 T 0.09546 G 0.02027 N 0.06755 U 0.03374 In Scheme, this is

(define freq-table '((e 0.12016) (t 0.09546) (a 0.07666) (o 0.07440) (i 0.07371) (n 0.06755) (r 0.06745) (s 0.06208) (h 0.04191) (l 0.04089) (d 0.03788) (c 0.03664) (u 0.03374) (m 0.02783) (p 0.02482) (f 0.02275) (g 0.02027) (b 0.01837) (y 0.01523) (w 0.01224) (x 0.00889) (v 0.00859) (k 0.00486) (q 0.00343) (z 0.00306) (j 0.00125)) ) Your program is to compute the chi squared value for each of the 26 possible Caesar ciphers, and use the cipher with the highest chi squared value to decode the text. As in part 1, a Scheme procedure should return the result. The procedures for the two parts of this problem can be used in conjunction for testing:

(decode (encode 5 sample-text)) If the sample text is sufficiently representative, the Caesar cipher selected to decode it should be the same as that used to encode it. Put your code and tests into a file named caesar.scm in your short-problems directory.

A4: Elevens

Write a program to play the solitaire game of Elevens. Elevens is played with the deck of 52 cards, with ranks A (ace), 2, 3, 4, 5, 6, 7, 8, 9, 10, J (jack), Q (queen), and K (king), and suits ♣ (clubs), ♦ (diamonds), ♥ (hearts), and ♠ (spades). Here is how you play:

1. Shuffle the deck. 2. Deal k cards from the deck to the table. 3. Repeat the following: Remove each pair of numeric cards (A, 2, ..., 10) that total 11, e.g. by removing an 8 and a 3 or a 10 and an A. Remove face cards in triplets (J, Q, and K). Ignore suits when determining what to remove. Deal cards from the deck to replace the cards just removed. 4. You win if you go through the entire deck and remove all the cards.

Here is an example game, with k = 6. cards on the table explanation K♠ 10♣ J♦ 2♦ 2♥ 9♣ initial deal K♠ 10♣ J♦ 7♣ 2♥ Q♠ discard 2♦ (either 2 would work) and 9♣ A♠ 10♣ 9♦ 7♣ 2♥ 7♦ discard J♦ Q♠ K♠ A♠ 10♣ 10♠ 7♣ 3♦ 7♦ discard 9♦ and 2♥ (discarding A and one of the 10's would have been legal here too) 2♠ 10♣ 9♠ 7♣ 3♦ 7♦ discard A♠ and 10♠ (10♣ could have been discarded instead) A♦ 10♣ K♣ 7♣ 3♦ 7♦ discard 2♠ and 9♠ 6♣ K♦ K♣ 7♣ 3♦ 7♦ discard A♦ and 10♣; no further plays are possible Write a procedure named elevens that, given a deck, plays the game and returns 1 for a win and 0 for a loss. Use the value 9 for k. Include your program elevens.scm in your short-problems directory along with a file of output named elevens.tests. 29.5.3 (Display page) Short problems, group B Group B: Practice with Higher-Order Procedures (do one problem from this group)

B1: Election Processing

Background

Presidential elections in the United States happen every four years. On November 2 of 2008, for instance, we chose between Barack Obama and John McCain for president. The procedure for determining the winner of the election is somewhat complicated, and is described here; in short, the candidate who gets the most popular votes in a particular state earns that state's electoral votes, and whoever gets more than half of all the electoral votes wins the election.

Assignment

Write and test a program to process U.S. presidential election results. The program will include a procedure named winner, whose first argument is a sentence giving the number of electoral votes for each state and whose second is a sentence giving the percentage of popular votes for the Republican and Democratic candidates. (For this assignment, we ignore third-party candidates.) Winner returns either republican, democrat, or #f, depending on who wins the election. Each word in the electoral vote sentence has four characters. The first two are the state abbreviation; the last http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 100 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

two are digits that together specify the number of electoral votes for the state. An example is ca55, which says that California has 55 electoral votes. Each word in the vote results sentence has six characters. The first two are the state abbreviation, as with the electoral votes sentence. The next two are the (rounded) percentage of popular votes earned by the Republican candidate; the last two are the percentage of popular votes earned by the Democrat candidate. Some examples from the 2000 election are George Bush earned 42% and Albert Gore earned 54% of the California ca4254 votes. dc0986 Bush earned 9% and Gore earned 86% of the District of Columbia votes. id6928 Bush earned 69% and Gore earned 28% of the Idaho votes. fl4949 Bush and Gore both earned 49% of the Florida votes. A framework file that provides the electoral votes for each state and the 2000 election returns is available here. You should use smaller test arguments. You should not make any assumptions about the order of words in the argument sentences, nor make assumptions about what the states are or how many of them are in the argument sentences. If both candidates get an equal percentage of votes in a state, neither candidate should get that state's electoral votes. Otherwise, every state is winner-take-all. That means there are two ways for winner to return #f. One is the situation where each candidate gets exactly half the total electoral votes. The other is where one candidate receives more votes than the other, but because of a tie in one or more states, the candidate with more votes doesn't get more than half the total.

Miscellaneous requirements

Put your solution program into a file named winner.scm in your short-problems directory, and your tests (described below) into a file named winner-tests.scm in the same directory. None of your code may use recursion. Use the higher-order procedures every, keep, and accumulate instead. In general, restrict your use of Scheme to material covered in Simply Scheme chapters 1-10. Your program should include auxiliary procedures to be called from winner; none of your procedures should be a big mess. You will lose points for unnecessarily duplicated code; define procedures with extra placeholders (possibly procedures) to avoid this duplication. Provide names for your procedures and their parameters that clearly indicate their types and use. Also provide comments with your code. Your grade on this assignment will include evaluation of your comments. Each of your procedures must be accompanied with comments that describe each input—is it a sentence, a word, or a number? what kind?—along with the result returned.

Testing

Include test expressions in a file named winner-tests.scm. Use the testing library discussed in earlier miniprojects (a full writeup of its functionality is available here). There is an additional feature described there: in run-test-cases, you can provide an optional argument to run only some of your test cases. Test winner on races where each candidate wins and where neither candidate wins. Include at least one input where two candidates split all the electoral votes evenly, and another where neither candidate earns half the votes. Also test your auxiliary procedures individually, to provide additional evidence that they work correctly. Any procedure that involves a numeric comparison should be tested with values less than, equal to, and greater than the compared value. Any procedure that includes a keep should be tested at least with one input for which all the elements are kept, another for which nothing is kept, and a third for which some but not all of the elements are kept. (Note that these tests are not guaranteed to remove all your bugs.)

B2: Blackjack Hand Improvement Checking

Background

The game of Twenty-One (also called "Blackjack") uses the standard deck of 52 cards. The object of the game is to be dealt a set of cards whose value is as close to 21 as possible but does not exceed 21. The value of a face card—jack, queen, or king—is 10. The value of an ace is either 1 or 11, whichever the player wants. The value of any other card is its face value. Twenty-One is played essentially as follows. A player is initially dealt two cards. Then the player asks for cards one at a time from the dealer until she decides to "stick" with the cards she has or her total exceeds 21. If her total exceeds 21, she immediately loses. Otherwise the dealer repeats the procedure of the player, drawing cards until either she loses by exceeding 21 or she decides to stick with the total she has. If neither the player nor the dealer has exceeded 21, the two hand totals are compared and the hand with the larger value wins. (There are several specialized hand-handling procedures that we will not consider here.) Expert Twenty-One players try to keep track of the cards remaining in the deck, in order to estimate better whether or not the next card dealt will improve their hand. For this assignment, you will write a program that a player could use for assistance.

Problem

Write a procedure draw-another? that, given a hand as its first argument and a deck as its second, returns true when at least half the cards in the deck will improve the value of the hand. Both the hand and the deck are represented as lists that each contain at least one card; a card is represented as a word whose first letter specifies the card's suit (s for spade, h for heart, d for diamond, c for club) and whose butfirst specifies the card's rank (one of a, 2, ..., 10, j, q, or k). For the purposes of this problem, a card improves the value of a hand exactly when adding the card to the hand results in a total that's closer to 21 without going over. To evaluate a hand, you should count an ace as 11 wherever possible; with a hand that contains an ace that counts as 11, a card that would force the ace to be counted as 1 should not be counted as improving the hand.

Examples

Listed below are some example calls to draw-another?, along with the values they should return and the reasons why. desired call explanation result

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 101 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

(draw-another? Since the hand total is less than 12, no card can '(h4 d5 d2) #t force it to go over 21. (An ace, if drawn, would be any-nonempty-deck) counted as 1.) (draw-another? The hand total is 17. Three cards&emdash;the '(h4 d5 d2 s6) #t ace (counting as 1), the 2, and the 4&emdash;out '(ha ck h2 s4 c5 d10) ) of the six in the deck improve the hand. The hand total is 17, with the ace counting as 11. (draw-another? Two cards in the deck, the ace (counting as 1) '(s6 ca) and the 2, improve the hand. Even though the 5 #f '(ha ck h2 and the 6 could result in a hand total less than 21, s5 c6 d10) ) they do not improve the hand since they lower the ace's value.

(draw-another? The hand total is 15, with the ace counting as 1. '(ca s6 h8) The ace, 2, 5, and 6 improve the hand. (Note that #t '(ha ck h2 draw-another?'s advice may not have been s5 c6 d10) ) followed to create the hand in the first place.) (draw-another? The hand value is 18, with one of the aces '(sa s6 ca) #f counting as 1 and the other counting 11. Only the '(ha ck h2 s5 c6 d10) ) ace and 2 improve the hand.

Miscellaneous requirements

Your program should include helper procedures to be called from draw-another? (for instance, a procedure to determine if a given card improves a hand); none of your procedures should be a big mess. Provide good names and comments for your procedures and their placeholders. Each of your procedures must be accompanied with comments that describe each argument—its type, plus whatever else you know about it—along with the result returned. Neither your draw-another? procedure nor any of your helper procedures should use recursion. Your helper procedures should be tested individually and together with the draw-another? procedure. Your tests should include at least the following situations:

cards of all ranks in the set {ace, king, queen, jack} plus a card of at least one other rank; a hand without aces; a hand with an ace that counts as 1; a hand with an ace that counts as 11; a hand with two aces, both counting as 1; a hand with two aces, one counting as 11; an ace in the deck that improves the hand counting either as 1 or as 11; an ace in the deck that improves the hand only counting as 1; a non-ace in the deck that improves the hand; a non-ace in the deck that busts an aceless hand; a non-ace in the deck that busts a hand with an ace that counts as 1; a deck in which exactly half the cards improve the hand; a deck in which less than half the cards improve the hand; a deck in which more than half the cards improve the hand; a deck in which none of the cards improve the hand.

Put your solution and test expressions in a file named draw-another.scm in your short-problems directory. If you work with a partner, include both your names in a comment in draw-another.scm. 29.5.4 (Display page) Short problems, group C Group C: Generalized List Structure (do one problem from this group)

C1: Directory Processing

Directories on your class account may contain other directories, which may contain other directories, and so on. Your files may thus be represented as a nested list, as pictured in the diagram below. A file that's not a directory is represented as a symbol; a directory is represented as a list whose first element is the symbol directory name, and whose remaining elements are the files and directories contained in the directory. directory structure Scheme representation

(a (b) c (d (e g h i) f) )

One often wishes to locate a file, that is, figure out how to get to it through the chain of directories that contain it. You are to write a procedure called path-to, which, when given arguments representing a file system and a file name, returns a list whose last element is the file name, whose first element is the name of the "root" file or directory, and whose other elements are the names of directories that must be opened to find the file. If no file with the given name is anywhere in the file system, your procedure should return #f. If a file with the given name appears twice or more in the file system, you may return the path to any of the files with that name. Test your procedure with the above directory, searching for the following files: name of file to search for list to return x #f b (a b) a (a) g (a d e g) i (a d e i) e (a d e)

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 102 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

C2: Evaluation of Arithmetic Expressions

Write a procedure arith-eval that works similar to Scheme's evaluation procedure when applied to expressions containing only arithmetic operations. Arith-eval will take two arguments: one is an expression, written in prefix notation as in Scheme, in which only the operators +, –, and * are used; the other is a table of variable-value associations. Evaluation of a variable in the expression—something that's not a number—should return the value associated with the variable. Note that arithmetic operators may take more than two arguments in Scheme. Some examples: expression returned value (arith-eval '(+ x) '((x 2) (y 1) (z 0))) 2 (arith-eval '(+ x y z) '((x 2) (y 1) (z 0))) 3 (arith-eval '(+ (* x z) (* 2 y) 13 (- 4 1)) 50 '((x 2) (y 14) (z 3))) You may assume that the expression argument is a legal Scheme expression in which the only procedure calls are to +, –, and *, and in which all variables used also appear in the table argument. Test your procedure on the above examples.

C3: Ancestors

Background

Consider a genealogical data base represented as a collection of nuclear families. Each nuclear family is a list whose first element is the name of the father (possibly the symbol unknown, if the father is not known), whose second element is the name of the mother (also possibly the symbol unknown), and whose remaining elements are the names of their children. Given below is a diagram for a family and the corresponding genealogical data base.

((nguyen deirdre suzanne) (arthur kate bruce charles david ellen) (frank rosa jose hillary) (bruce suzanne tamara vincent) (jose ellen ivan julie marie) (andre hillary nigel) (unknown tamara frederick) (vincent wanda zelda) (ivan wanda joshua) (quentin julie robert) (nigel marie olivia peter) (robert zelda yvette) (peter erica diane) )

Some interesting features of this family: Marie has married her first cousin Nigel. Wanda has had one child with Vincent and another with Ivan. Zelda and Robert, the parents of Yvette, have two great grandparents in common. And only Tamara knows who Frederick's father is, and she's not telling.

Problem

Write a procedure ancestors that, given a data base and a person in the data base as arguments, returns a list of ancestors of that person. (A person's ancestors are his or her parents plus the ancestors of his or her parents.) You may assume that the data base is a legal one, that the given person is somewhere in the data base, and that no two people in the data base have the same name. However, as in Yvette's case, a person may be an ancestor of another in more than one way; the list returned by ancestors should not return duplicate names. Test your procedure at least on a person with no ancestors, on Yvette, and on Frederick using the given data base (online in the file ~cs3/lib/family.db.scm). 30 Today's activities 2009-11-12 ~ 2009-11-13 (1 activity) 30.1 Project or short problems checkoff(1 step) 30.1.1 (Display page) Checkoff requirements Checkoff requirements

To earn full credit for today's project/short problems checkoff, you must answer the following questions for your t.a.

Will you be working with a partner? If so, who? (If your partner is in a different lab section, you will have to get checked off by both t.a.s.) Will you be working on a project, or on short problems? (The short problems will prepare you better for the final exam. The only penalty you pay for working on short problems is that your http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 103 of 104 Curriculum Builder Portal 2/11/10 9:26 AM

course grade is capped at B+.) What part of the project, or which short problem, will you work on in preparation for next week's checkoff?

31 Today's activities 2009-11-17 ~ 2009-11-18 (2 activities) 31.2 More to do(1 step) 31.2.1 (Display page) Work on your project Work on your project

In the remainder of today's section, we encourage you to work on your project. There will be a project checkoff on Thursday and Friday, where you should be prepared to demonstrate significant progress on your project or on the short problems. 32 Today's activities 2009-11-19 ~ 2009-11-20 (1 activity) 32.1 Project/short problems checkoff(1 step) 32.1.1 (Display page) Checkoff requirements Checkoff requirements

By Thursday/Friday, November 19 or 20 (whenever you have lab), you must display significant progress on the project: some procedures coded and tested, with a fairly detailed plan for proceeding on the rest. (The individual project writeups have suggestions for what to provide.) We are looking for about 25% of the code completed. If you're doing short problems, you need to have at least one of them solved. If you do not meet this milestone during your lab, you will lose 45% of your total project score. 33 Today's activities 2009-11-24 ~ 2009-11-25 (1 activity) 33.1 Project work; no quiz today(1 step) 33.1.1 (Display page) Project work Project work

You should work on your project (or short problems) today. There will be a checkpoint a week from today, at which you will demonstrate substantial progress on the project program (which should be mostly completed), or display two completed solutions to short problems. There will be no more quizzes this semester. Happy Thanksgiving! 34 Today's activities 2009-12-01 ~ 2009-12-02 (1 activity) 34.1 Project/short problems checkoff; no quiz today(1 step) 34.1.1 (Display page) Checkoff requirements Checkoff requirements

By Tuesday/Wednesday December 1 or 2 (whenever you have lab), you must display a mostly complete project solution. (The individual project writeups have suggestions for what to provide.) If you're doing short problems, you need to have at least two of them solved. If you do not meet this milestone during your lab, you will lose 45% of your total project score.

http://fall09.ucwise.org/builder/builderPortal.php?BUILDER_menu=curriculumSummary Page 104 of 104