COMP203: Lecture 10


Syllabus | Homework and Assignments | Grading Rubric | Midterm Exam | Final Project

When circumstances allow, I'll be typing up bits of my lecture notes and posting them online. These may or may not bear any resemblance to the actual lectures.

Predicates and Logical Connectives

As suggested on page 72 of the text, create a plumbing diagram for:
print ifelse emptyp :a [emptyp :b] [emptyp :c]
(If you run this instruction in Logo you will find that :a has no value. That's ok -- this is a sample instruction and not one we will use.)

If you finish early, create a plumbing diagram for this instruction from last class:

 if (or (memberp "computer :sentence) (memberp "computers :sentence) ~
        (memberp "programming :sentence))~
    [output "true]
Remember, the first input to if or ifelse is a true/false value and the remaining input or inputs are lists of instructions. The English sentence "if it rains, I will bring an umbrella" might look like:
if rainp [bring "umbrella]
in Logo. Similarly, the instruction "I wear sunglasses if it's sunny" might look like:
if sunnyp [wear "sunglasses]
The English language is very flexible. Logo is not.

A few weeks ago, a student entered the following command while trying to draw a circle:

repeat 360 [forward 10 right 1]
run it and see what happens.

When the turtle runs off the top of the Logo window it reappears at the bottom. Think of what else you might want the turtle to do when it tries to leave the Logo window -- maybe it should stop dead, maybe an error message should appear, or maybe it should "bounce back" into the Logo window.

The Logo operation pos outputs a list describing the turtle's position on the screen. Use the instruction show pos and some turtle motion instructions to guess the boundaries of the Logo window.

Write and test a predicate that checks to see whether the turtle is close to th e window boundary -- you probably want to use a predicate like greaterp or lessp as a helper procedure.

Now we're ready to change the way the turtle behaves near the window boundary. Ultimately we'd like to replace the forward command, but first let's just test our predicate. Below is a procedure wander with helper procedure turnaround which moves the turtle 300 steps in a random direction, reversing the turtle's direction if predicate offscreen returns a value of true.

to wander ; Procedure to test predicate offscreen
 repeat 300 ~
  [
   forward 1
   wait 1
   if offscreen [turnaround]
  ]
end 

to turnaround ; Helper for wander which reverses the turtle's direction.
 setheading sum heading 180
end
Feel free to replace turnaround by some other procedure if you wish the turtle to do something else near the edge of the screen.

Once procedure wander works the way you want it to, it should be fairly simple to create a procedure newforward based on wander. If you do so, test it on the instruction:

repeat 360 [newforward 10 right 1]
Does it behave the way you expect?

Functions of Functions

Chapter 5 is titled "Functions of Functions"; on page 84 the author explains that to him this means tools that repeatedly apply the same function.

As you probably know, there are some tasks computers are good at and some that they aren't. You should use a computer if you're trying to find a children's book with the word "apple" in the title whose author's last name starts with K. On the other hand, if you're looking for a book with a picture of an apple on the cover that describes all the things you can cook using apples, you should ask a librarian.

The computer solves the first problem by looking through a list of all children's books whose authors' names start with K for ones that have "apple" in the title. The computer can read this list much more quickly than the librarian, so this is a good task for a computer.

In general, computers are very good at doing simple, repetitive tasks -- checking each title for the word "apple", adding numbers on a spreadsheet, or producing frames for an animated movie. So far, the only tool we've seen to do the same thing over and over is repeat. Chapter 5 presents more tools for doing this.

repeat

The Logo command repeat accepts two inputs. The first input is the number of times to repeat a list of instructions, and the second input is the list of instructions to repeat.

Examples:

repeat 4 [forward 80 right 90]
repeat 20 [repeat 30 [type "&] print []]

for

The repeat command is useful, but not very flexible. It does exactly the same thing over and over; searching the same title for the world "apple" over and over is not very useful, nor is adding the same number over and over. What do we use if we want to advance through a list of titles or numbers?

The Logo command for advances through a list of numbers (and so can advance through a numbered list). For example:

for [i 1 10] [print :i]
for [i 1 10 2] [print :i]
for [j 10 4 -1] [print :j]
for [size 10 150 10] [forward :size right 60]
Procedure for requires two inputs. The first input describes the way in which Logo will advance (or retreat) through a sequence of values, and the second input is a list of instructions to implement for each value in the sequence.

More specifically, the first input to for provides three or four values: the name of an index variable (which will be local to the for statement), a starting value for that variable, an ending value for that variable, and an optional "increment" value that tells you how much to advance (or decrease) the variable by at each step. While the start and end values are usually positive integers and the step size is usually 1, you can use any values you like here.

for [i -2.3 6.7 3.3] [print :i]
Note that the for command only executes the instructions in its second input for values of the variable beteween the start and end values -- if the value of the index variable overshoots the end value, for stops before running the instructions in the second input.

Practice using the for command. One fun way to do this is by experimenting with different shapes of spirals:

for [size 10 150 10] [forward :size right 60]
If you finish early, try to write an operation using for that accepts a positive integer n as an input and outputs the sum 1 + 2 + 3 + ... + n.

while

The text makes a big fuss about map, which is a Logo procedure that applies a function to each item in a list, but doesn't mention while. However, while is a common command in programming languages (including Maple) and map is not; this semester we will study while and not spend much time on map.

? help "while
WHILE tfexpression instructionlist			(library procedure)

	command.  Repeatedly evaluates the "instructionlist" as long as the
	evaluated "tfexpression" remains TRUE.  Evaluates the first input
	first, so the "instructionlist" may never be run at all.  The
	"tfexpression" must be an expressionlist whose value when evaluated
	is TRUE or FALSE.
From the help information, we learn that while requires two inputs: a true/false expression and a list of instructions. Like repeat and for, while executes those instructions over and over. Unlike repeat and for, we can't always tell by looking at the inputs to while how many times those instructions will be run.

Last class we wrote a maze game. Here's another maze game that uses while. You remain lost if you turn left and you fall in a pit if you do anything else. Copy and run it to see how it works.

to maze
 local "response
 make "response "left
 while [equalp :response "left] ~
       [print [You are lost in a scary maze.  Will you go left or right?]
        make "response readword]
 print [You fell in a pit.  You lose.]
end
Important note: The first input to while in this example is a list. The while command evaluates the instructions in the list repeatedly until the result is false. This is different from the if and ifelse commands, whose first input is usually the output of a predicate. The first input to while is usually a predicate and its inputs inside square brackets.

Below is a procedure that uses while to very roughly estimate the square root of a number by squaring numbers until the result exceeds the number input. I've written it as a command rather than as an operation because Logo has a perfectly good sqrt operation for when we need a square root.

to estimatesqrt
 local "number
 local "counter
 print [Type in a number and I will estimate its square root.]
 make "number readword
 make "counter 0
 while [lessp :counter*:counter :number] [print :counter make "counter :counter+1]
 print (sentence [The square root of] :number [is between] :counter-1 "and word :counter ".)
end
Try this procedure out.
? estimatesqrt
Type in a number and I will estimate its square root.
8
0
1
2
The square root of 8 is between 2 and 3.
? 
Can you make one simple change to the procedure to change the display to:
? estimatesqrt
Type in a number and I will estimate its square root.
8
1
2
3
The square root of 8 is between 2 and 3.
? 
Would tildes (~) and line breaks make the while command more readable here? Try it!

Do you think you could write this procedure using for and stop? How or why not?