Spring 1996
Homework 2, problem 1 asks you to determine how many calls are made to a function. (You should give the total number of calls, including the initial one.) Donkey can help you with this homework. One strategy is to just step through evaluation of the entire expression, noting when you reduce a function call. But there is an easier way.
In Donkey, pull down the Stop-at menu, then select apply. Now when you click on the Step button, Donkey will proceed until the next evaluation rather than stopping at every evaluation step. You can basically just count the number of times you click on Step.
Another way to do your homework is to reason about the programs: take a look at what they are doing, and try to figure out how they should behave.
The way that I did the homework was to write a program to compute the answers for me. A function to determine the number of calls made is only a trivial modification of the functions whose behavior you are examining. If you make just a few careful changes, you'll get a function that tells you how many calls the original function would have made. (Of course, the new function tells you nothing about what value the original function would have returned, but we're not interested in that.)
By loading a special set of Scheme procedures, you can make your computer talk. To load the Comp 210 sound library, evaluate the following expression (use DrScheme, not Donkey).
(load "/home/comp210/sounds/sound-library.ss")The double quote marks set off a new type of value called a string. A string is somewhat like a symbol, in that it consists of any sequence of characters. Here, the string specifies the file containing the Scheme code.
This file defines the following Scheme variables:
speak-word
is a procedure that takes a symbol or a
non-negative integer less than 100 as its argument and causes the
computer to pronounce the word.speak-list
is a procedure that takes a list of symbols and
integers as its argument; each of the words is pronounced in turn.
(Exercise: how could you write speak-list
in terms of
speak-word
?)word-defined?
is a procedure that takes a symbol or integer
as its argument and returns #t
if the computer knows how to
pronounce that word and #f
if the computer cannot pronounce that
word. (In Scheme, we put a question mark at the end of a procedure that
returns a boolean value. It's not required, but it improves the
readability of the program.)defined-words
is a list of all the words the computer knows
how to pronounce. Some small integers are omitted from this list, but
the computer can still pronounce every number from 0 to 99.
Do some experiments with these procedures. For instance, try
(speak-list (cons 'artichokes (cons 'are (cons 'awesome null))))We learned in lecture that the
list
function also creates lists,
so the above is equivalent to
(speak-list (list 'artichokes 'are 'awesome))
Since the sound can be annoying to others in the lab, consider placing your hand over the speaker (over the holes on the front left of the machine) to muffle the sound.
There are several potential sources of trouble when loading the file sound-library.ss. Check that you spelled the name of the file correctly:
(load "/home/comp210/sounds/sound-library.ss")Also, make sure you use
(load "...")
and not DrScheme's
File - Open... menu.
For now, don't read big files into the DrScheme editing window; that's too
slow. Also, load
only works intermittently under Donkey, so don't
run the load
command from Donkey yet.
If you get the complaint
"/dev/audio": no such filethen maybe your machine doesn't have sound. The SPARCstation 5s in the front of Ryon 102 have sound, but the SPARCstation 4s in the back of Ryon 102 don't. To find out for sure, try running this command (from a command shell such as an xterm window, not from Scheme):
cat /home/comp210/sounds/bark.au > /dev/audioIf it makes a noise like a dog coughing, then your machine has sound. If not, move to another machine that says ``SPARCstation 5'' on the front.
If you enter the
command and Scheme just sits there for more
than about a second, then another program may have control of the speaker.
Only one program can use sound at a time. So, kill any other copies of
DrScheme or Donkey (or anything else that uses sound). Even Web pages can
contain sound, so you might have to kill Netscape, but that's probably not
necessary. Also, it is possible in rare cases for a program to go into a
dormant state (even if its windows is gone from the screen), in which case
killing it is more involved. Try logging out and logging back in, or
moving to a different machine if all else fails.
load
DrScheme and Donkey are sometimes unreliable; sound is particularly effective in frightening DrScheme (and causing the program to quit).
If you have this problem you might want to know about another implementation of Scheme called Chez Scheme. It is considerably more robust, though it lacks some of the features of DrScheme and Donkey. It does not run in its own window, does not step through expression evaluation, and does not permit convienient editing of previously-evaluated expressions.
To run Chez Scheme, type scheme at a command shell. (Don't put an
ampersand (&
) after the command.) You will shortly get a >
prompt. At the prompt, you can type any Scheme expression. For instance,
you could load the sound library, then call
and
speak-word
.
speak-list
In Chez Scheme, you may need to use the delete key (to the right of
the main keyboard on the SPARCstation 5 keyboards) rather than the
backspace key. To break out of whatever you are doing and get a new
prompt, press control-c (hold down control, press and
release c, let up on control).
When you are done with Chez Scheme, execute the function
to
leave:
exit
(exit)
In the next lab, we will see another way to edit programs, and to run Chez Scheme from that editor, somewhat like DrScheme.
Recall from class the four-step method for defining Scheme procedures:
In class, we followed these steps for the function
, that
takes a list member?
and a symbol l
as input and determines
whether or not the symbol appears in the list.
Let's do the same for s
, which returns the length of a list.
(We won't call it lingth
, because DrScheme already has a function
of that name and is very protective of it. Chez Scheme is less picky and
will let you use whatever name you like.)
length
A list is either
null
, or(cons hd tl)
, where hd is a scheme value
symbol (like the symbol 'mike
) and tl is a list.
tl
is shorter than the list (cons hd tl)
. Similarly,
when we write a function, the recursive call must given a simpler argument
(such as a shorter list or a smaller number) than the current call got.
The corresponding schema for writing a rule R to process lists is
(define R (lambda (l) (if (null? l) ... ... (car l) ... (R (cdr l)) ... )))
The first ellipsis
is an expression specifying
what answer the rule produces for the empty list. (The expression doesn't
include ...
because we already know everything there is to know
about it--it is exactly the empty list.) The second expression
l
constructs the answer for a
non-empty list ... (car l) ... (R (cdr l)) ...
. This expression may invoke the rule l
recursively to process R
, and it may also examine the first
element of the non-empty list (cdr l)
. (Either or both of these
subexpressions may be omitted, if desired.) Note that the rule includes a
recursive call to l
for each recursive reference in the definition.
One R
is sufficient because there are only two possibilities for
if
; if there are more possibilities, we need more l
expressions, or we can use a different operator called if
.
cond
The rule defining the function
is an instance
of the preceding schema:
lingth
(define lingth (lambda (l) (if (null? l) 0 (+ 1 (lingth (cdr l))))))
One way to think about recursive programming is in terms of wishful
thinking. While writing
, at one point we said, ``I wish I
had a function that I could use to determine the length of the lingth
rest of the list; then I could use that to determine the length of the
whole list.'' We just pretended that we already had such a
thing--called cdr
--and proceeded. Then, before we
knew it, we really did have lingth
!
lingth
Type the definition of
and test it on some lists. You
should get the same answers as from the built-in function lingth
.
length
When doing the following exercises, remember to write a schema that follows the data definition for the input.
Define the function
, which is like member-count
,
except that it returns a number indicating the number of
times that the symbol appears in the list. For instance,
member?
Challenge: Your solution probably contains an=>
(member-count (list 'a 'b 'a 'c 'a) 'a)
3
=>
(member-count (list 'a 'b 'a 'c 'a) 'z)
0
if
and a call to
+
. Can you change the order of those operations?
Define the function
, which returns the
nth element in a list.
For instance,
nth
=>
(nth (list 'a 'b 'c 'd 'e) 2)
'b
=>
(nth (list 'a 'b 'c 'd 'e) 5)
'e
Write a function
that takes a list as input and
determines whether it is a list of numbers. The Scheme operation
list-of-numbers?
determines whether or not a Scheme datum is a number.
number?
DrScheme makes it easy to express Scheme programs in a consistent, readable format. Your programs should conform to the indentation conventions supported by DrScheme. If a program definition is not properly indented, you can use the command Indent All on the Scheme menu to indent it properly, subject to the line breaks in the definition. Indent All will not change line breaks.
As you enter a program definition, DrScheme automatically indents each line properly, but there are a few conventions that you must observe in making line breaks to produce programs with the proper layout.
The following rules provide simple guidelines for inserting line breaks. If you follow these rules, your code will be eaiser to read and understand. Don't forget to make the indentation right: in Donkey, DrScheme, or Emacs, just type TAB while the cursor is anywhere on a line, and that line will be correctly indented relative to the line just above it.
lingth
, we put
(define lingthon a line by itself.
lambda
and
the accompanying list of input variables on a separate line.
(define lingth (lambda (l)
if
expression, put line breaks after the condition and
after the true consequent.
(define lingth (lambda (l) (if (null? l) 0 (+ 1 (lingth (cdr l))))))
There is a separate set of rules for
conditionals; we will
introduce those next week when we learn about cond
.cond
cond
, see next week's tutorial notes.
DrScheme has many useful editing commands that were not mentioned in the first laboratory. The Edit menu contains seven commands: Undo, Redo, Clear, Copy, Cut, Paste, and Find. Most of these commands involve selected text. You can select text in DrScheme by placing the cursor on the first character of the desired selection, pressing the left mouse button, moving the cursor just past the last character in the selection, and releasing the mouse button. The selection is highlighted whenever the mouse points to the DrScheme window.
The edit menu commands have the following functions:
Try using each of these commands. Enter some garbage in your dictionary and use Undo to erase it. Try using Redo to reverse the process of undoing commands.
DrScheme also supports many commands that are invoked from the keyboard. Some useful keystroke commands are Tab, Control-f, Control-b, Control-n, Control-p, Control-a, Control-e, Control-d, and Control-k. The Control key is a form of ``shift key''. For example, Control-d is the character d typed while the Control-key is depressed. These keystroke commands have the following functions:
Save your dictionary and then experiment with these keystroke editing commands.
DrScheme catches two different forms of Scheme program errors. First,
it notices when you try to load ill-formed programs from the dictionary window
into the evaluation window. In this case, it pops up a window identifying
the error and asking you what to do next. The obvious response is to click
on the button that aborts loading the program text, then edit your dictionary
to correct the specified error. The second form of error detection is
more subtle. During program execution, a program operation can be applied
to invalid data. Examples include peforming arithmetic on inputs
that are not numbers, dividing by zero, and applying
or car
to the empty list. In this case, DrScheme aborts
program execution, prints a message explaining why, and places an
ugly black square on the operation that is being applied to illegal data.
cdr
Load the file error.ss into the dictionary window and try following sequence of experiments:
fact
is ill-formed because it is missing
a closing parenthesis. Fix the error and Execute the dictionary
again.(fact 5)
. Observe that execution aborts and identifies
the culprit as the function application (* n (fact (sub1 n)))
when n
is 1
and (fact (sub1 n))
is the empty list.fact
in the dictionary
window, reload it in the evaluation window, and evaluate (fact 5)
and (fact 500)
.
If you inadvertently start executing a function that never terminates, you can usually break out of it by selecting the Stop Executing button at the top of the window. At this point, DrScheme will type a new prompt in the evaluation window
and wait for you to enter a new expression in the evaluation window or new definition in the dictionary window.>
Edit the definition of
by changing fact
to (sub1 n)
. Load the dictionary into the evaluation window and try
evaluating n
. Use the Stop Executing button
to stop execution.
(fact 5)