COMP203: Lecture 8

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.

Quiz today!

Start thinking about your midterm project.

Review of Operations

We ended last class with a discussion of operations -- procedures that output values to other procedures, as opposed to commands which have an effect like printing, displaying an image on the screen, saving a file, or picking up the turtle's pen.

Below is a procedure that outputs the tangent of an angle.

to tan :angle
  output quotient sin :angle  cos :angle
end
Remember that this is an operation, not a command, so to run this procedure without errors you must start your complete instruction with a command. For example:
? print tan 180
-0
? print tan 60
1.73205080756888
? print tan 45
1
?
For example, we might use this function to write a procedure to draw a circle with a given diameter.
to circle :diameter
  repeat 360 [forward product tan .5 :diameter right 1]
end

Write an arcsin function

Logo comes with an arctan function, but not an arcsin or arccos function, although these might be useful to find a turning angle for the turtle in some drawing.

A few calculations starting from a right triangle with hypotenuse of length 1 shows us that:
arcsin y = arctan( y / (sqrt(1-y2))).

Write a Logo procedure arcsin which accepts a number between -1 and 1 as input and outputs the arcsin of that number.

Newton's Method

Newton's method is a technique which uses the value of a function f and its derivative to improve estimates of the x-intercept of the graph of y=f(x) as shown in the picture below. If we have Logo operations that output the value of a function and its derivative for a given input, we can then program Logo to apply Newton's method.

Choose an algebraic function whose graph has an x-intercept -- for example, f(x) = x^2 - 1 or f(x) = x^3.

Write an operation function which accepts a value :x as input and outputs the value of your function when it's evaluated at :x. Test your procedure as shown below:

? print function 1
0
? print function 2
3
? print function 0
-1
Next, write an operation derivative which accepts one input and outputs the slope of the graph of the function at that input. Your procedure may use the derivative of the function or it may compute the slope of a secant. Test your procedure.

Once you've written your function and derivative procedures, the Logo operation improve_guess defined below should accept a guess at an x-intercept as input and output an improved guess. (The formula used to improve the guess came from solving the formula given in the figure for the variable "new".)

to improve_guess :guess
  output :guess - (function :guess) / (derivative :guess)
end
To apply "Newton's method" to find the x-intercept, continue improving a guess until the output of function is close enough to 0 for your purposes. (Or until it's obvious that the method isn't working.) Use a global variable or instructions like:
print improve_guess improve_guess 0
to see how close you can get to the value of the x-intercept of your function.

If you finish this task with time to spare, experiment with the difference between using the derivative to find the slope and using the formula for the secant line to find the slope. How small does the value of the variable "dx" have to be in order to get good results? This could be an interesting research project!

Chapter 4

Conditional Evaluation

Why do we need it?

In Chapter 1 we saw a quiz program which did different things depending on whether you agreed with the author's taste in music or not:
to music.quiz
  print [Who is the greatest musician of all time?]
  if equalp readlist [John Lennon] [print [That's right!] stop]
  print [No, silly, it's John Lennon.]
end
Last class we used Newton's method to improve our guess at the x-intercept of a function until we had an estimate we liked. To decide whether we liked an estimate, we plugged it back in to the function to see how close to zero the function was at that point. If we know how close is "close enough" -- say, less than .05 units away from the x-axis -- we could use Logo to check to see when our estimate is good enough. To do this we'll need instructions like if used in the quiz program.

Predicates

According to the author, your choice of favorite musician is either right or wrong; there's no partial credit. For most computers, the electrical impulses which power them are either on or off; there's no partway on. Based on the states of off and on, computers are ideally well suited to handle true/false and yes/no questions. In fact, the underlying design of most computer systems is formal logic.

In Logo, a predicate is a procedure which always outputs one of two values: true or false. The predicate equalp from music.quiz is an example of a predicate.

Experiment with equalp and see how it works; use instructions like:

print equalp [John Lennon] [Lennon]
print equalp 6 sum 3 3
print equalp "01 1
print equalp [a] "a
What do you think the predicates lessp, numberp, emptyp and memberp do? Use help, the examples below, and some experimentation to find out!
print lessp 3 5
print lessp 5 3 
print memberp "t "that
print memberp "t [a e i o u]
print emptyp butfirst "t
print numberp "01

Predicates are fundamental to the workings of a computer program, but in Logo they aren't mysterious or complicated. They're just operations that output true or false. We can write our own predicates!

If you were writing a Wheel of Fortune computer game, you might need to check whether a letter is a vowel or consonant. The textbook has offers the following procedure:

to vowelp :letter
  output memberp :letter [a e i o u]
end
Here's how we might use predicate vowelp:
to chooseletter
  local "letterchoice
  print [Pick a letter]
  make "letterchoice readword
  if vowelp :letterchoice [print [You must pick a consonannt.] make "letterchoice chooseletter]
  output :letterchoice
end
What does this procedure do? Can you use Logo's count operation to make sure the user's choice is a single letter?

Another example in the book is the predicate oddp, which uses the operation remainder to see if a number is divisible by 2:

to oddp :number
  output equalp (remainder :number 2) 1
end
Can you write a predicate which tells whether its input divisible by 10? What should you name this predicate?

Debugging

Now that we're writing more complicated procedures, this is a good time to look at some of the tools we can use to fix procedures that don't work.

You've already seen the edit tool and the help tool. These are the two most important tools you have for figuring out and fixing problems in Logo, but they're not your only tools.

Broken procedures are easier to fix if you know what they're doing. Procedure house had comments written into the code to indicate what each line does:

to square :sidelength
 repeat 4 [forward :sidelength right 90]
end

to house                                                               
 square 100 ; frame
 right 90 forward 50 left 90 ; move to door
 square 30 ; door
 penup forward 50 left 90 forward 20 right 90 pendown ; move to window
 square 15 ; window
 penup back 50 right 90 back 30 left 90 pendown ; move back to start
end
To add a comment to a procedure, start with a semicolon (;) and follow it with your comment. (Also, try to avoid using semicolons elsewhere in your programming.)

Using comments in your procedures will help you remember what you were thinking as you wrote each line. This will help you fix procedures that don't work, it will help me understand what you were trying to do with your procedures, and it may increase your grade on the assignment (beyond just making it easier to get the right answer!)

When these three basic tools fail, Logo provides you with some fancier tools. They're cumbersome, so you might not want to use them often.

The command step requires one input which is the name of a procedure (or a list of names of procedures). When you run a procedure whose name has been given to step, Logo will print each line in the procedure before running it. This is a good thing to try if your procedure is doing something unexpected -- you can isolate the line on which the unexpected thing happens, then use a plumbing diagram to analyze that line.

? step "house
? house
To stop stepping through a procedure, use the command unstep.

The command trace requires one input which is a procedure name or list of procedure names.

? trace "square
? house
Every time the procedures named are run, Logo prints the instruction that uses the procedure. trace is a good tool to use if you have a complicated program and you're not sure what part of the program is causing the problem. trace is only useful for debugging procedures that use helper procedures (e.g. house, but not square or triangle.) To stop tracing a procedure, use the command untrace.

The command pause stops a procedure when it reaches a certain point and gives you a Logo prompt to use to determine what variables have what values at that point in the program. You can learn more about pause on pages 293-295 of Chapter 15.