1 Prologue: How to Program
When you were a small child, your parents probably taught you to count and
later to perform simple calculations with your fingers: “1 + 1 is 2”; “1 +
2 is 3”; and so on. Then they would ask “what’s 3 + 2” and you would count
off the fingers of one hand. They programmed, and you computed. And in
some way, that’s really all there is to programming and computing.
Start DrRacket and choose “Beginning Student Language” from
the “How to Design Programs” submenu in the “Language” menu.
Now you’re switching roles. You program, and the computer is a child. Of
course, you start with the simplest of all calculations. You type
into the top part of DrRacket, click RUN, and a result shows up in the
bottom part: 2

That’s how simple programming is. You ask questions as if DrRacket were
a child, and DrRacket computes for you. People often say the
“computer computes for you” but in reality, a plain computer is pretty
useless to most people. It is software that really makes
computers useful, it is just difficult to get used to saying “the
software computes for you.” You can also ask DrRacket to process several
requests at once:
| (+ 2 2) |
| (* 3 3) |
| (- 4 2) |
| (/ 6 2) |
After you click RUN, you see
4 9 2 3
in the bottom half of DrRacket, which are the correct results. This means that DrRacket knows a lot
about arithmetic, far more than a small child. Indeed, DrRacket knows
about squaring numbers, exponents, and even trigonometry:
When you click RUN now, DrRacket’s bottom half displays four
numbers:
9 8 0 -1.0
Take a close look at the last number. Its “#i” prefix is short for “I
don’t really know the precise number so take that for now.” Unlike your
calculator or most other programming systems, DrRacket is extremely
honest. When it doesn’t know the exact number, it warns you with this
special prefix. Later, we shall show you really strange facts about
“computer numbers,” and you will then truly appreciate that DrRacket
issues such warnings.
Terminology: At this point, we should slow down for just a
moment and introduce some words:
The top-half of DrRacket is called the definitions
area. This area is where you create the programs, which is called
editing. As soon as you add a word or change something in the
definitions area, the SAVE button shows up in the top-left
corner. When you click SAVE for the first time, DrRacket asks
you for the name of a file, which is a place on your computer
(technically, its disk) where DrRacket stores your program for
good. Once your definitions area is associated with a file, clicking
SAVE just ensures that the content of the definitions area is
stored safely in the file.
Programs consist of expressions. For now,
programs are expressions.
You have seen expressions in mathematics. For now, an
expression is either a plain number or something that starts with a left
parenthesis “(” and ends in a matching right parenthesis “)”—which
DrRacket rewards by displaying a gray box.
When you click RUN, DrRacket evaluates an expression at a
time and displays the result in the interactions area. Then,
DrRacket, your faithful servant, awaits your commands at the prompt and
you can enter additional expressions though they disappear next time you
hit RUN:
Enter your first program at the prompt, hit the “return” or “enter” key on
your keyboard, and watch how DrRacket responds with the result. You can do
so as often as you wish:
| > (+ 2 2) |
4 |
| > (* 3 3) |
9 |
| > (- 4 2) |
2 |
| > (/ 6 2) |
3 |
| > (sqr 3) |
9 |
| > (expt 2 3) |
8 |
| > (sin 0) |
0 |
| > (cos pi) |
#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i#i-1.0 |
Enough memorizing.
By now, you might be wondering whether DrRacket can add more than two
numbers at once, and yes, it can! As a matter of fact, it can do it in two
different ways:
| > (+ 2 (+ 3 4)) |
9 |
| > (+ 2 3 4) |
9 |
The first one is nested arithmetic, as you know it from school.
The second one is Racket arithmetic and it is natural, if you
always use parentheses to group operations and numbers
together. This as a good a time as any to discuss the nature of
our notation—dubbed Beginning Student Language or just
BSL—something you might have pondered for a while now.
You might be thinking that you’re learning Racket because the
software application is called DrRacket. Not true. You are learning a series
of teaching languages created for this book, starting with BSL. Once you
have mastered these languages though, you can quickly learn all kinds of
full-fledged programming languages, including Racket but also JavaScript,
Perl, Python, Ruby, and other such scripting languages.
In BSL, every time you want to use a “calculator operation,” you write
down an opening parenthesis followed by the operation, the numbers on
which the operation should work (separated by spaces or even line breaks),
and ended by a closing parenthesis. The items following the operation are
called the operands. Nested arithmetic means that you can use an
expression for an operand, which is why
is a fine program. You can do this as often as you wish:
| > (+ 2 (+ (* 3 3) 4)) |
15 |
| > (+ 2 (+ (* 3 (/ 12 4)) 4)) |
15 |
| > (+ (* 5 5) (+ (* 3 (/ 12 4)) 4)) |
38 |
There are no limits to nesting, except for your patience.
Naturally, when DrRacket calculates for you, it uses the rules that you know
and love from math. Like you, it can determine the result of an addition
only when all the operands are plain numbers. If an operand is a
parenthesized operator expression—something that starts with a “(” and
an operation—it determines the result of that nested expression
first. Unlike you, it never needs to ponder with which expression to
calculate first—because this first rule is the only rule there is to
it.
The price for DrRacket’s convenience is that parentheses have meaning. You,
the programmer, must enter all these parentheses, and you may not enter too
many. For example, while extra parentheses are acceptable to your math
teacher, this is not the case for BSL. The expression
(+ (1) (2))
contains way too many parentheses, and DrRacket lets you know in no uncertain terms:
| > (+ (1) (2)) |
function call: expected a function after the open |
parenthesis, but found a number |
Once you get used to BSL programming though, you will see that it
isn’t a price at all. First, you get to use operations on several
operands at once, if it is natural to do so:Or you place the
cursor next to the operation and hit F1. This action opens DrRacket’s HelpDesk
and searches for the documentation of the operation. Use the results
concerning the HtDP teaching languages. As you may have noticed by now,
this text is also linked to the documentation in HelpDesk.
| > (+ 1 2 3 4 5 6 7 8 9 0) |
45 |
| > (* 1 2 3 4 5 6 7 8 9 0) |
0 |
If you don’t know what an operation does for several operands, enter an
example into the interactions area and hit "return"; DrRacket lets
you know whether and how it works. Second, when you will read programs that
others write—which you will do for about half the time of your
programmer life—you will never have to wonder which expressions are
evaluated first. The parentheses and the nesting will immediately tell
you so.
In short, to program is to write down comprehensible, arithmetic
expressions, and to compute is to determine their value. With DrRacket, it is
easy to explore this kind of programming and computing.
1.1 Arithmetic and Arithmetic
If programming were just about numbers and arithmetic, it would be as
boring as mathematics.Just kidding: mathematics is a fascinating
subject, but you knew that. You won’t need too much of it for now, though
if you want to be a really great programmer, you will need to study some.
Fortunately, there is much more to programming than numbers: text,
truths, images, and more.
Here are three programs that deal with text:
After you click RUN, DrRacket displays three results:
"helloworld" "hello world" "hello world"
To understand exactly what’s going on, you first need to know that in BSL,
text is any sequence of keyboard characters enclosed in double-quotes
("). Technically, this is called a string. Thus,
"hello world", is a perfectly fine string and, when DrRacket evaluates this
string, it displays it in the interactions area, just like a number.
Indeed, many people’s first program is one that displays the words
“hello” and “world”—you wrote three of them already but the simplest one is to type
in the string by itself:
Click RUN and admire the output of the program.
Otherwise, you need to know that in addition to an arithmetic of numbers,
DrRacket also knows about an
arithmetic of strings. Thus,
string-append is an operation just like
+; it makes a
string by adding the second to the end of the first. As the first line
shows, it does this literally, without adding anything between the two
strings: no blank space, no comma, nothing. Thus, if you want to see the
phrase
"hello world", you really need to add a space to one of
these words somewhere; that’s what the second and third line show. Of
course, the most natural way to create this phrase from the two words is
to enter
because
string-append, like
+, can deal with as many
operands as you wish.
You can do more with strings than append them. You can extract pieces from
a string; reverse strings; make all letters uppercase (or lowercase) in a
string; strip blanks spaces from the left and right; and so on. And best
of all, you don’t have to memorize any of that. If you need to know what
you can do with strings, look it up in HelpDesk. Use F1 or
the drop-down menu on the right to open HelpDesk, look at the manuals for
HtDP languages (BSL) and its section on primitives. It lists all the
operations in BSL and especially those that work on strings.
If you did look up the primitive operations of BSL, you saw that
primitive (also called built-in) operations can consume
strings and produce numbers. You therefore can, if you so desire,
add the length of a string to 20:
and DrRacket evaluates this expressions like any other one.
That is, an arithmetic operation doesn’t have to be about just numbers or
just strings. Many of them mix and match as needed. And then there are
operations that convert strings into numbers and numbers into strings and
you get what you expect:
If you expected “fortytwo” or something clever along those lines,
sorry, that’s really not what you want from a string calculator.
The second expression raises a question, though. What if
string->number
isn’t used with a string that is a number wrapped in string quotes? In that
case the operation produces a totally different kind of result:
This is neither a number nor a string; it is a
Boolean. Unlike numbers
and strings, Boolean values come in only two varieties:
true and
false. The first is truth, the second falsity. Even so, DrRacket
has several operations for combining Boolean values:
and you get the results that the name of the operation suggests. (Don’t
know what
and,
or, and
not compute? Easy:
(and x y) is true if
x and
y are true;
(or x y) is true if either
x or
y or both are
true; and
(not x) results in
true precisely when
x is
false.)
Although it isn’t possible to convert one number into a Boolean, it is certainly
useful to “convert” two numbers into a Boolean:
Guess what the results are before you move on:
true
true
false
Now try these: (>= 10 10), (<= -1 0), and
(string=? "design" "tinker"). This last one is totally different
again but don’t worry, you can do it.
With all these new kinds of data—yes, numbers, strings, and
Boolean values are data—and operations floating around, it is easy to
forget some basics, like nested arithmetic:
What is the result of this expression? How did you figure it out? All by
yourself? Or did you just type it into DrRacket’s interactions area
and hit the "return" key? If you did the latter, do you think you would
know how to do this on your own? After all, if you can’t predict what
DrRacket does for small expressions, you may not want to trust it when
you submit larger tasks than that for evaluation.
Before we show you how to do some “real” programming, let’s discuss one
more kind of data to spice things up: images. To inset
images such as this rocket into DrRacket, use the Insert menu and
select the “Insert image ...” item. Or, if you’re reading this book
on-line, copy-and-paste the image from your browser into DrRacket. When you
insert an image into the interactions area and hit return like this
> 
DrRacket replies with the image. In contrast to many other programming
languages, BSL understands images, and it supports an arithmetic of
images just as it supports an arithmetic of numbers or strings. In short,
your programs can calculate with images, and you can do so in the
interactions area. Furthermore BSL programmers—like the programmers for
other programming languages—create libraries that others may
find helpful. Using such libraries is just like expanding your
vocabularies with new words or your programming vocabulary with new
primitives. We call such libraries teachpacks because they are
helpful with teaching.
(require 2htdp/image) specifies that you wish to add
the "image" library. Alternatively, use the “Language” drop-down
menu, choose “Add Teachpack ...” and pick "image".
One important library—
"image"—
supports operations for computing
the width and height of an image:
Once you have added a library to your program, clicking RUN gives
you
1176
because that’s the area of a 28 by 42 image.
You don’t have to use Google to find images and insert them in your DrRacket
programs with the “Insert” menu. You can also instruct DrRacket to
create simple images from scratch:
If you are reading the paper version of the book, though, you
only see a gray circle and a gray, outlined rectangle.
What you should see is a solid red circle of radius 10 and the
blue outline of a 30 by 20 rectangle:

Naturally BSL has operations for combining images:
produces a red circle on a solid blue square background:
Overlaying the same images in the opposite order, like this,
produces a solid blue square

Now you know that overlay is more like string-append
than +, but it does “add” images just like
string-append “adds” strings and + adds numbers.
Do yourself a favor and look up the documentation for overlay/xy
in HelpDesk. Then experiment with the function, which is also available
through the "2htdp/image" teachpack.
You should know about two more operations:
empty-scene and
place-image. The first creates a scene, a special kind of
rectangle. The second places an image into such a scene:
and you get this: Not quite. The image comes without a
grid. We superimpose the grid on the empty scene so that you can see
where exactly the green dot is placed.
As you can see from this image, the origin (or (0,0)) is in the upper-left
corner. Unlike in mathematics, the y coordinate is measured
downwards, not upwards. Otherwise, the image shows what you should
have expected: a solid green disk at the coordinates (50,80) in a 100 by
100 empty rectangle.
Let’s summarize again. To program is to write down an arithmetic
expression, but you’re no longer restricted to boring numbers. With BSL,
your arithmetic is the arithmetic of numbers, strings, Boolean values, and
even images. To compute though still means to determine the value of the
expressions(s) except that this value can be a string, a number, a
Boolean, or an image.
And now you’re basically ready to write programs that make rockets fly.
1.2 Inputs and Output
The programs you have written so far are pretty boring. You write down an
expression or several expressions; you click RUN; you see some
results. If you click RUN again, you see the exact same results. As
a matter of fact, you can click RUN as often as you want, and the
same results show up. In short, your programs really are like calculations
on a pocket calculator, except that DrRacket calculates with all kinds
of data not just numbers.
That’s good news and bad news. It is good because programming and computing
ought to be a natural generalization of using a calculator. It is bad
because the purpose of programming is to deal with lots of data and to get
lots of different results, with more or less the same calculations. (It
should also compute these results quickly, at least faster than we can.)
That is, you need to learn more still before you know how to program. No
need to worry though: with all your knowledge about arithmetic of numbers,
strings, Boolean values, and images, you’re almost ready to write a program
that creates movies, not just some silly program for displaying “hello
world” somewhere. And that’s what we’re going to do next.
Just in case you didn’t know, a movie is a sequence of images that are
rapidly displayed in order. If your algebra teachers had known about the
“arithmetic of images” that you saw in the preceding section, you could
have produced movies in algebra instead of boring number
sequences. Remember those tables:
x = | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
y = | 1 | 4 | 9 | 16 | 25 | 36 | 49 | 64 | 81 | ? |
Your teachers would show you those, and then they’d ask you to fill in the
blanks (replace the “?” marks).
It turns out that making a movie is no more complicated than completing a
table of numbers like that. Indeed, it is all about such tables:
To be concrete, your teacher should ask you here to draw the sixth image,
the seventh, and the 1273rd one because a movie is just a lot of
images, some 20 or 30 of them per second. So you need some 1200 to 1800
of them to make one minute’s worth of it.
You may also recall that your teacher not only asked for the fifth, sixth,
or seventh number in some sequence but also for an expression that
determines any element of the sequence from a given x. In the
numeric example, the teacher wants to see something like
this:Write x2 if you want to be fancy.
If you plug in 1, 2, 3, and so on for x, you get 1, 4, 9, and so on for
y—just as the table says. For the sequence of images, you could say
something like
y = the image that contains a dot x2 pixels below the top.
The key is that these one-liners are not just expressions but functions.
At first glance functions are like expressions, always with a y on the
left, followed by an = sign, and an expression. They aren’t expressions,
however. And the notation you (usually) learn in school for functions is
utterly misleading. In DrRacket, you therefore write functions a bit
differently:
The
define says “consider
y a function”, which like
an expression, computes a value. A function’s value, though, depends on
the value of something called the
input, which we express with
(y x). Since we
don’t know what this input is, we use a name to represent the
input. Following the mathematical tradition, we use
x here
to stand in for the unknown input but pretty soon, we shall use all kinds
of names.
This second part means you must supply one value—a number—for
x to determine a specific value for y. When you do,
DrRacket plugs in the value for x into the expression
associated with the function. Here the expression is (* x x). Once x is replaced with a value, say 1, DrRacket
can compute the result of the expressions, which is also called the
output of the function.
Click RUN and watch nothing happen. Nothing shows up in the
interactions area. Nothing seems to change anywhere else in
DrRacket. It is as if you hadn’t accomplished anything. But you
did. You actually defined a function and informed DrRacket about its
existence. As a matter of fact, the latter is now ready for you to use the
function. Enter
at the prompt in the interactions area and watch a 1 appear in
response. The (y 1) is called a function application in
DrRacket.... and in mathematics, too. Your teachers just
forgot to tell you. Try
and see a 4 pop out. Of course, you can also enter all these
expressions in the definitions area and click RUN:
| (define (y x) (* x x)) |
| |
| (y 1) |
| (y 2) |
| (y 3) |
| (y 4) |
| (y 5) |
In response, DrRacket displays:
1 4 9 16 25,
which are the numbers from the table. Now determine the missing entry.
What all this means for you is that functions provide a rather economic way
of computing lots of interesting values with a single expression. Indeed,
programs are functions, and once you understand functions well, you know
almost everything there is about programming. Given their importance,
let’s recap what we know about functions so far. First,
(define (FunctionName InputName) BodyExpression)
is a
function definition. You recognize it as such, because it
starts with the word “
define,” a
keyword or marker whose sole
purpose is to distinguish a definition from expressions. A function
definition consists of three pieces: two names and an expression. The
first name is the name of the function; you need it to apply the function
as often as you wish. The second name—
most programmers call it a
parameter—
represents the input of the function, which is unknown
until you apply the function. The expression, dubbed
body
computes the output of the function for a specific input. Naturally, the
expression may consist of many other expressions, as we have seen in the
first two sections.
Second,
(FunctionName ArgumentExpression)
is a function application. The first part tells DrRacket which
function you wish to use. The second part is the input to which you wish
to apply the function. If you were reading a Windows or Mac manual, it
might tell you that this expression “launches” the (software)
“application” called FunctionName and that it is going to
process ArgumentExpression as the input. Like all expressions,
the latter is possibly a plain piece of data (number, string, image,
Boolean) or a complex, deeply nested expression.
Functions can input more than numbers, and they can output all kinds of
data, too. Our next task is to create a function that simulates the
second table—
the one with images of a gray dot—
just like the first
function simulated the numeric table. Since the creation of images from
expressions isn’t something you know from high school, let’s start
simply. Do you remember
empty-scene? We quickly mentioned it at
the end of the previous section. When you type it into the definitions
area, like that:
clicking RUN produces an empty rectangle, also called a scene:

produces an scene with a rocket hovering near the center of the top:

Think of the rocket as an object that is like the disk—though more
interesting—in the above table from your mathematics class.
Next you should make the rocket descend, just like the disk in the above
table. From the preceding section you know how to achieve this effect by
increasing the
y coordinate that is supplied to
place-image:
Clicking RUN yields three scenes:



All that’s needed now is to produce lots of these scenes easily and to
display all of them in rapid order.
The first goal can be achieved with a function of course:
Yes, this is a function definition. Instead of y, it uses the
name create-rocket-scene, a name that immediately tells you what
the function outputs: a scene with a rocket. Instead of x, the
function definition uses height for the name of its parameter, a
name that suggests that it is a number and that it tells the function
where to place the rocket. The body expression of the function is just
like the series of expressions with which we just experimented, except
that it uses height in place of a number. And we can easily
create all of those images with this one function:
| (create-rocket-scene 0) |
| (create-rocket-scene 10) |
| (create-rocket-scene 20) |
| (create-rocket-scene 30) |
Try this out in the definitions area or the interactions area, both
create the expected scenes.
(require 2htdp/universe)
The second goal requires knowledge about one additional primitive operation
from the
"universe" library:
animate. So, add the
require line to the definitions area, click
RUN, and
enter the following expression:
As soon as you hit the “return” key, DrRacket evaluates the expression but
it does not display a result, not even an interactions prompt (for a while).
Yes, the operand is a function. Don’t
worry for now about using functions as operands with animate but
don’t try this on your own for now.
It does open another window—
a
canvas—
and runs a little
“movie” that shows the rocket descending from the top of the screen to
the bottom where it then disappears.
You should eventually dismiss this extra window. If you “kill” the
window, DrRacket will display a number in the interactions area; the number
indicates the current height of the rocket at that point. Also
click STOP to see how that works out.
The question is where the images on the window come from. The short
explanation is that
animate runs its operand on the numbers
0,
1,
2, etc. and displays the resulting
images. The long explanation is this:
animate starts a clock, and animate counts the
number of clock ticks;
the clock “ticks” ticks 28 times per second;
every time the clock ticks, animate applies the function
create-rocket-scene to the current clock tick; and
the scene that this application creates is displayed on the screen.
This means that the rocket first appears at height 1, then
2, then 3, etc., which explains why the rocket descends
from the top of the screen to the bottom. That is, our three-line program
creates some 100 pictures in about 3.5 seconds, and displaying these
pictures rapidly creates the effect of a rocket descending to the ground.
Here is what you learned in this section. Functions are useful because they
can process lots of data in a short time. You can launch a function by
hand on a few select inputs to ensure it produces the proper outputs. This
is called testing a function. Or, DrRacket can launch a function on
lots of inputs with the help of some libraries; when you do that, you are
running the function. Naturally, DrRacket can launch functions when
you press a key on your keyboard or when you manipulate the mouse of your
computer. To find out how, keep reading. Whatever triggers a function
application isn’t important, but do keep in mind that (simple) programs
are just functions.
1.3 Many Ways to Compute
When you run the create-rocket-scene program from the preceding
section, the rocket eventually disappears in the ground. That’s plain
silly. Rockets in old science fiction movies don’t sink into the ground;
they gracefully land on their bottoms, and the movie should end right
there.
This idea suggests that computations should proceed differently, depending
on the situation. In our example, the create-rocket-scene program
should work “as is” while the rocket is in-flight. When the rocket’s
bottom touches the bottom of the screen, however, it should stop the
rocket from descending any further.
In a sense, the idea shouldn’t be new to you. Even your mathematics
teachers define functions that distinguish various situations:
This sign distinguishes three kinds of inputs: those
numbers larger than 0, those equal to 0, and those smaller than 0. Depending on the
input, the result of the function—or output as we may occasionally call
it—is +1, 0, or -1.
Open a new tab in DrRacket and start with a clean slate.
You can define this function in DrRacket without much ado using a
conditional expression:
| (define (sign x) |
| (cond |
| [(> x 0) 1] |
| [(= x 0) 0] |
| [(< x 0) -1])) |
| |
| (sign 10) |
| (sign -5) |
| (sign 0) |
To illustrate how sign works, we added three applications of the
function to the definitions area. If you click RUN, you see
1, -1, and 0.
In general, a conditional expression has the shape
| (cond |
| [ConditionExpression1 ResultExpression1] |
| [ConditionExpression2 ResultExpression2] |
| .... |
| [ConditionexpressionN ResultExpressionN]) |
That is, a
conditional expressions consists of many
conditional lines. Each line contains two expressions: the left
one is often called
condition and the right one is called
result.
This is a good time to explore what the
STEP button does. Click STEP for the above
sign program. When the new window comes up, click the right and
left arrows there. To evaluate a
cond expression, DrRacket
evaluates the first condition expression,
ConditionExpression.
If the evaluation of
ConditionExpression1 yields
true,
DrRacket replaces the
cond expression with the first result
expression (
ResultExpression1) and evaluates it. Whatever value
DrRacket obtains is the result of the entire
cond expression.
If the evaluation of
ConditionExpression1 yields
false,
DrRacket drops the first line and moves on to the second line, which is
treated just like the first one. In case all condition expressions
evaluate to
false, DrRacket signals an error.
Figure 1: Landing a rocket (version 2)
With this knowledge, you can now change the course of the simulation. The
goal is to not let the rocket descend below the ground level of a
100 by 100 scene. Since the create-rocket-scene function consumes
the height at which it is to place the rocket in the scene, a simple test
comparing the given height to the maximum height appears to suffice.
See
figure 1 for the revised function definition.
In BSL, you can really use all kinds of characters in
function names, including “.” or “-” which you have already seen. We
call the revised function create-rocket-scene.v2 to distinguish it from the original
version. Doing so also allows us to use both functions in the interactions
area of DrRacket and to compare their results:
| > (create-rocket-scene 5555) |

|
| > (create-rocket-scene.v2 5555) |

|
No matter what number over 100 you give to
create-rocket-scene.v2, you get the same scene. In
particular, when you run the simulation
the rocket descends, sinks half way into the ground, and finally comes to
a halt.
Landing the rocket half-way under ground is ugly. Then again, you basically
know how to fix this aspect of the program. As you learned from the
preceding sections, DrRacket knows an arithmetic of images. Images have
a center point and, when place-image adds an image to a scene, it
uses this center point as if it were the image. This explains why the
rocket is half way under ground at the end: DrRacket thinks of the
image as if it were a point, but the image has a real height and a real
width. As you may recall, you can measure the height of an image with the
operation image-height, which is to images like + is to
numbers. This function comes in handy here because you really want to fly
the rocket only until it bottom touches the ground.
Putting one and one together—also known as playing around—you can now
figure out that
is the point at which you want the rocket to stop its descent. Hint: you
could figure this out by playing with the program directly. Or you can
experiment in the interactions area with your image arithmetic. Enter
this expression, which is one natural guess:
and then this one:
Which result do you like better?
Figure 2: Landing a rocket (version 3)
When you think and experiment along these lines, you eventually get to the
program in figure 2.
Given some number, which represents the height of the rocket, it
first tests whether the rocket’s bottom is above the ground. If it is, it
places the rocket into the scene as before. If it isn’t, it places the
rocket’s image so that its bottom touches the ground.
1.4 One Program, Many Definitions
Now imagine this. Your manager at your hot game company doesn’t like flight
simulations where rockets that sink halfway into the ground. Worse, all of
a sudden, this manager requests a version of the game that uses
200 by 400 scenes. This simple request forces you to
replace 100 with 400 in five places in the program, which
includes the animate line, and to replace 100 with
200 in three other places. Before you read on, try to do just that
so that you get an idea of how difficult it is to execute this request for
a five-line program. As you read on, keep in mind that real programs
consists of 50,000 or 500,000 or 5,000,000 lines of code.
In the ideal program, a small request, such as changing the sizes of the
canvas, should require an equally small change. The tool to achieve this
simplicity with BSL is
define. In addition to defining functions,
you can also introduce
variable definitions, which assign some
name to a constant. The general shape of a variable definition is
straightforward:
(define VariableName Expression)
Thus, for example, if you write down
in your program, you are saying that HEIGHT always
represents the number 100. The meaning of such a definition is
what you expect. Whenever DrRacket encounters HEIGHT during its
calculations, it uses 100 instead. Of course, you can also add
to your program to have one single place where you specify the width of
the scene.
Figure 3: Landing a rocket (version 4)
Now take a look at the code in
figure 3, which implements this
simple change. Copy the program into DrRacket, and after clicking
RUN, evaluate the following interaction:
Confirm that the program still functions as before.
The program in figure 3 consists of three definitions: one
function definition and two variable definitions. The number
100 occurs only twice: once as the value of WIDTH and
once as the value of HEIGHT. The last line starts the
simulation, just as in version 3 of the program. You may also have noticed
that it uses h instead of height for the function
parameter of create-rocket-scene.v4. Strictly speaking, this
change isn’t necessary because DrRacket doesn’t confuse height with
HEIGHT but we did it to avoid confusing you.
When DrRacket evaluates (animate create-rocket-scene.v4),
it replaces HEIGHT with 100 and WIDTH with 100
every time it encounters these variable names. To experience the joys of real
programmers, change the 100 next to HEIGHT into a 400
and click RUN. You see a rocket descending and landing in a 100 by 400
scene. One small change did it all.
In modern parlance, you have just experienced your first program
refactoring. Every time you re-organize your program to prepare yourself
for likely future change requests, you refactor your program. Put it on
your resume. It sounds good, and your future employer probably enjoys
reading such buzzwords, even if it doesn’t make you a good programmer.
What a good programmer would never live with, however, is that the program
contains the same expression three times:
Every time your friends and colleagues read this program, they need to
understand what this expression computes, namely, the distance between the
bottom of the screen and the center point of a rocket resting on the
ground. Every time DrRacket computes the value of the expressions it
has to perform three arithmetic operations: (1) determine the height of the
image; (2) divide it by 2; and (3) subtract the result from
100. And every time it comes up with the same number.
This observation calls for the introduction of one more definition to your
program:
plus the replacement of every other occurrence of
(- 100 (/ (image-height
) 2)) with
ROCKET-CENTER-TO-BOTTOM.
You might wonder whether the new definition should be placed
above or below the definition for
HEIGHT. More generally, you should
be wondering whether the ordering of definitions matters. The answer is that
for variable definitions, the order matters, and for function definitions
it doesn’t. As soon as DrRacket encounters a variable definition, it
determines the value of the expression and then associates the name with
this value. Thus, for example,
is meaningless because DrRacket hasn’t seen the definition for
CENTER yet when it encountered the definition for
HEIGHT. In contrast,
works as you would expect. First, DrRacket associates
CENTER with
100. Second, it evaluates
(* 2 CENTER), which yields
200. Finally, DrRacket associates
200 with
HEIGHT for the rest of the computation.
Figure 4: Landing a rocket (version 5)
You may find it surprising, though, that it doesn’t matter whether you
first define the variables in your program or the function(s). Indeed, if
your program consisted of more than one function, it wouldn’t matter in
which order you defined them. Still, it is good to first introduce all the
constants, followed by all the important functions and then the less
important ones. We know that because you haven’t yet created a program
with more than one function definition yet, this discussion is all
theory. You will define and enjoy such programs sooner than you know it,
however, and then it all becomes practice.
The program also contains two line comments,
introduced with semi-colons (“;”). While DrRacket ignores such comments,
people who read programs should not because comments are intended for
human readers. It is a “back channel” of communication between the
author of the program and all of its future readers to convey information
about the program—without making DrRacket do anything about it.
Once you do all these things, you get the program in figure 4.
It consists of one function definition and five variable definitions.
In addition to the computation that determines the distance between the
rocket’s center and the bottom of the scene, these variable definitions
also factor out (as in “refactor”) the image itself as well as the
creation of the empty scene.
Before you read on, ponder the following changes to your program:
How would you change the program to create a 200 by 400 scene?
How would you change the program so that it depicts the landing of a
green UFO (unidentified flying object)? Drawing the UFO per se is easy:
How would you change the program so that the background is always
blue?
How would change the program so that the rocket lands on a flat rock
bed that is 10 pixels higher than the bottom of the scene? Don’t forget to
change the scenery, too.
Better than pondering is doing. It’s the only way to learn. So don’t let
us stop you. Just do it.
1.5 One More Definition
Danger ahead! This section introduces one piece of knowledge
from physics. If physics scares you, skip this section on a first reading;
programming doesn’t require physics knowledge.
Real rockets don’t descend at a constant speed. Real cars don’t stop on the
spot. They decelerate, which is the opposite of accelerate. What this
really means is that an object first travels at a constant speed and then
the driver hits the breaks or the pilot fires some engines. The effect of
using the breaks or firing the engines is to change the speed
slowly—decelerate in fancy English.
To understand how this process works precisely, you must think back to your
physics courses in ninth grade. If you haven’t because you’re too young or
if you can’t remember because you’re too old or if you skipped this
course, you need to look in a physics book. Don’t worry. This happens to
programmers all the time because they need to help people in music,
physics, mechanical engineering, economics, photography, and all kinds of
other disciplines and, obviously, not even programmers know everything. So
they look it up. Or they are told what the process of deceleration means
for the distance that an object travels:
That is, if v is the speed of the object and a is the
deceleration—change of speed—then the object travels d
miles/meters/pixels in t seconds.
By now you know that a good teacher would have shown you a proper function
definition:
because this tells everyone immediately that the computation of d
depends on t and that v and a are constants. A programmer would go
even further and use meaningful names for these one-letter things:
This program consists of three definitions: a function that computes the
distance traveled by a decelerating object; its velocity or speed for you;
and its change in speed or deceleration. The
distance function
uses a primitive operator called
sqr; if you can’t figure out
what it does, play with it in the interactions area or look it up in
HelpDesk.
The next and only other thing you need to know is that
animate actually applies its functions to the number of
clock ticks that have passed since it was first called and
not the
height of the rocket image. From this revelation it immediately follows
that our five versions of
create-rocket-scene have thus far used
the wrong name for the input. Clearly,
t—
short for time—
would
be much better than
h, which is short for height:
| (define (create-rocket-scene t) |
| (cond |
| [(<= t ROCKET-CENTER-TO-BOTTOM) |
| (place-image ROCKET 50 t MTSCN)] |
| [(> t ROCKET-CENTER-TO-BOTTOM) |
| (place-image ROCKET 50 ROCKET-CENTER-TO-BOTTOM |
| MTSCN)])) |
More importantly, however, this small change to the definition also
clarifies that this program doesn’t compute how far the rocket has
traveled in the given time; it uses the time as if it were a distance.
| ; properties of the “world” |
| (define WIDTH 100) |
| (define HEIGHT 100) |
| |
| ; properties of the descending rocket |
| (define V 20) |
| (define DECELERATION 1) |
| |
| ; various other constants |
| (define MTSCN (empty-scene WIDTH HEIGHT)) |
(define ROCKET ) |
| (define ROCKET-CENTER-TO-BOTTOM |
| (- HEIGHT (/ (image-height ROCKET) 2))) |
| |
| ; programs |
| (define (create-rocket-scene.v6 t) |
| (cond |
| [(<= (distance t) ROCKET-CENTER-TO-BOTTOM) |
| (place-image ROCKET 50 (distance t) MTSCN)] |
| [(> (distance t) ROCKET-CENTER-TO-BOTTOM) |
| (place-image ROCKET 50 ROCKET-CENTER-TO-BOTTOM MTSCN)])) |
| |
| (define (distance t) |
| (- (* V t) (* 1/2 DECELERATION (sqr t)))) |
Figure 5: Landing a rocket (version 6)
Even if you have never taken a physics course, you know that a time is not
a distance. So somehow our program worked by a little bit of an
accident. Don’t worry, though; it is all easy to fix. Instead of
t, we use
(distance t), and we add the above definitions
to our program. The final program is displayed in
figure 5.
It consists of two function definitions:
create-rocket-scene.v6
and
distance. The remaining variable definitions make the function
definitions readable and modifiable. As always, you can run the program by
supplying one of its functions to
animate:
In comparison to the previous versions of create-rocket-scene,
this final version teaches you that a program may consist of more than one
function definition and that one function definition
(create-rocket-scene.v6) can refer to other function
definitions (distance).
In a way, this revelation shouldn’t surprise you. Even the first version of
create-rocket-scene used + and / and other
functions. It’s just that you think of those as built into
DrRacket. While + and / are indeed an intrinsic part
of the programming language, some others are not. For example, most of the
“image arithmetic” and a good part of the “string arithmetic” are just
function definitions that we created a long time ago and that are added to
your definitions area when you click RUN.
As you become a true blue programmer you will find out that programs consist of
many function definitions and many variable definitions. You will also see
that functions refer to each other all the time. What you really need to
practice is to organize such collections of definitions so that you can
read them easily even months after completion. After all, you or your
manager will want to make changes to these programs, and if you don’t know
how to read them and if you didn’t organize them well, you will have a
difficult time with even the smallest task. Otherwise you mostly know what
there is to know and you can program.
1.6 You are a Programmer Now
The claim that you are a programmer may have come as a surprise to you at
the end of the preceding section but it is true. You know all the
mechanics that there is to know. You know that programming and computing
is about arithmetic of numbers, strings, images, and whatever other data
your chosen programming languages supports. You know that programs consist
of function and variable definitions. You know, because we have told you,
that in the end, it’s all about organizing these definitions
properly. Last but not least, you know that DrRacket and the teackpacks
support lots of other functions and that DrRacket HelpDesk explains
what these functions do.
You might think that you still don’t know enough to write programs that
react to keystrokes, mouse clicks, and so on. As it turns out, you do. In
addition to the animate function, the "universe" teachpack
provide other functions that hook up your programs to the keyboard, the
mouse, the clock and other moving parts in your computer. Indeed, it even
supports writing programs that connect your computer with anybody else’s
computer around the world. So this isn’t
really a problem.
From a theoretical perspective, you are missing one piece of the puzzle:
the ability to define functions that, when called, compute forever. This
may sound useless and difficult to achieve. It is neither. Here is how you
define such a program:
| (define (run ul) |
| (run 42)) |
| |
| (run 5) |
If you click RUN, you get no result. Actually, you should
immediately move the mouse to the STOP button, click, hold the
mouse button down, and wait for DrRacket to stop your run-away
program.
In short, you have seen almost all the mechanics of putting together
programs. If you read up on all the functions that are available, you can
write programs that play interesting computer games, run simulations, or
keep track of business accounts. The question is whether this really means
you are a programmer.
Stop! Think! Don’t turn the page yet. |
1.7 Not!
When you look at the “programming” book shelves in any random book store
of some unnamed book chain not to speak of certain parts of college book
stores, you will see loads of books that promise to turn lead into gold,
that is, make you a programmer in 21 days or faster. There are also books
by cautious authors who think you need to stretch the same or similar
material over the entire course of a semester. If you have worked through
the first six sections of this book, however, you know that neither of
these approaches can create a solid understanding of programming.
Acquiring the mechanical skills of programming—learning how to write
instructions or expressions that the computer understand, getting to know
what functions are available in the libraries, and similar
activities—aren’t helping you much with real programming. To make
such claims is like saying that a 10-year old who knows how to dribble can
play on a professional soccer (football) team. It is also like claiming
that memorizing 1,000 words from the dictionary and a few rules from a
grammar book teaches you a foreign language.
Programming is far more than the mechanics of language acquisition. It is
about reading problem statements, extracting the important concepts. It is
about figuring out what is really wanted. It is about exploring examples
to strengthen your intuitive understanding of the problem. It is about
organizing knowledge and it is about knowing what you don’t know yet. It
is about filling those last few gaps. It is about making sure that you
know how and why your code works, and that you and your readers will do so in
the future. In short, it is really about solving problems systematically.
The rest of this book is all about these things; very little of the book’s
content is about the mechanics of BSL or other HtDP languages. The book
shows you how good computer programmers think about problems,
and—promise!—you will even learn to see that these ideas of problem
solving apply to other situations in life, e.g., the work of doctors and
journalists, lawyers and engineers, or car mechanics and photographers.
Oh, and by the way, the rest of the book uses a tone that is appropriate
for a serious text.
What the book is not about: Many early books on
programming and even some of today’s books teach you a lot about the
authors’ favorite application discipline for programming: mathematics,
physics, music, accounting, and so on. To some extent that is natural,
because programming is useful in those areas. Then again, it forces you to
know a lot (or at least something) about those disciplines. This book
really focuses on programming and problem solving and what computer
science can teach you in this regard. We have made every attempt to
minimize the use of knowledge from other areas; for those few occasions
when we went too far, we apologize.