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.
Below is a procedure that outputs the length of the hypotenuse of a right triangle when given the lengths of the legs of the triangle.
to hypotenuse :leg1 :leg2 output sqrt (:leg1 * :leg1 + :leg2 * :leg2) endRemember 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 hypotenuse 3 4 print hypotenuse 5 12

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 -1Next, write an operation slope which accepts one input and outputs the slope 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 slope procedures, the Logo operation improve_guess defined below should be 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) / (slope :guess) end"Newton's method" is just to continue improving a guess until the result is close enough to an x-intercept. (Or until it's obvious that the method isn't working.) Use a global variable or instructions like:
improve_guess improve_guess 0to 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!
In some sense, the difference between print and output is who the procedure reports to. If you use print, the procedure displays the value for you to see. If you use output, the value goes to the command or operation below your procedure in the plumbing diagram. You may never see the value that your procedure computes.
In order for your procedure to fit anywhere but the bottom of a plumbing diagram, it has to output a value to the procedure below it in the plumbing diagram. It's nice if you can tell from a procedure what f(1) is, but for the example we just worked through the procedure improve_guess might also need to find out the value of f(1). That's why procedure function was written as an operation and not a command.
? print query [I should have known better] should I have known better? ? print query [you are experienced] are you experienced?We want to write a procedure query that accepts one input: a list. The output of that procedure should be a new list in which the first and second elements are swapped and a question mark is added to the end.
Here are some things we know about Logo that will help us with this:
to query :phrase output sentence :phrase "? endIf we test this, we can see that it's not as good as the example in the book:
? print query [I should have packed a lunch] I should have packed a lunch ? ?If we want to score 100% on this problem we have to fix two problems: move the ? closer to the last word of the phrase, and swap the first two words in the phrase. Swapping the first two words seems to be a more important change than moving the question mark, so let's work on that.
The first word of the phrase is first :phrase and the second is first butfirst :phrase (or item 2 :phrase). We can put these words together using sentence:
to query :phrase output sentence (first butfirst :phrase) (first :phrase) endSo far, this looks like a step back:
? print query [I should have packed a lunch] Should I ?We need to add the rest of the phrase and the question mark to our output. We'll start by adding the question mark because that's easy and illustrates an important shortcut.
We could do the following:
to query :phrase output sentence (sentence (first butfirst :phrase) (first :phrase)) "? endHere, procedure sentence combines the second and first words of the phrase and outputs the resulting list to procedure sentence. Then sentence adds a question mark to the end of the list. The new list is output to output, which outputs the value and ends the procedure. (You might want a plumbing diagram for this instruction.)
Using sentence twice to put three words together is painful; we'll need to use it at least once more to get the output we actually want. There is an easier way!
Look at the help entry for sentence:
? help "sentence
SENTENCE thing1 thing2
SE thing1 thing2
(SENTENCE thing1 thing2 thing3 ...)
(SE thing1 thing2 thing3 ...)
outputs a list whose members are its inputs, if those inputs are
not lists, or the members of its inputs, if those inputs are lists.
The first two lines indicate that sentence expects two inputs. But the third and fourth
line of the help seem to allow for three or more inputs.Some Logo procedures, like word, sum, product, and list, are programmed to allow two or more inputs. If you include extra inputs, you must use parentheses to indicate what procedure they are inputs to and where the list of inputs ends. For example:
print (sentence "The [quick brown] "fox) print (sum 1 2 3 4 5) print (word "a "lp "ha "b "et)Another example appeared in our procedure hypotenuse:
to hypotenuse :leg1 :leg2 output sqrt (:leg1 * :leg1 + :leg2 * :leg2) endHere, the parentheses surround the Logo operation + and its inputs. (For more information on operations like + and *, see page 29 of Chapter 2.)
So our procedure above could be:
to query :phrase output (sentence (first butfirst :phrase) (first :phrase) "?) endMuch nicer! Can you figure out how to use butfirst to complete the phrase? If you can do this and finish early, look at some examples from Chapter 1 and try to use word to attach the question mark correctly.
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 endTo 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 ? houseTo 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 ? houseEvery 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.
to primer :name print (sentence first :name [is for] word :name ".) print (sentence "Run, word :name ", "run.) print (sentence "See :name "run.) endIs this procedure an operation or a command?
Procedure primer is more difficult to use than procedure converse from chapter 1 because you have to know in advance what input it's expecting.
? primer "Fred F is for Fred. Run, Fred, run. See Fred run. ? primer [Fred Flintstone] word doesn't like [Fred Flintstone] as input in primer [print (sentence first :name [is for] word :name ".)] ? primer not enough inputs to primer ?Here's another example, that requires two inputs:
to primer2 :firstname :lastname print sentence [A student named ] :firstname print [took a class on Logo.] print sentence [The teacher said hey ] :lastname print [and helped to make the code go.] endNote that help "primer gives us a hint on how to run the procedure, but doesn't tell us whether the procedure expects a word or a list (or a number) as input.
to primer3 local "name ; Avoids creating a global variable print [What is your name?] ; Run the program, *then* ask for input make "name readword ; This gets and stores the name print [] print (sentence first :name [is for] word :name ".) print (sentence "Run, word :name ", "run.) print (sentence "See :name "run.) endThe operation readword outputs a word that you type at the keyboard, just as readlist was an operation which output a list typed at the keyboard.
Try it out!
? primer3 What is your name? Fred F is for Fred. Run, Fred, run. See Fred run.The Logo command make requires two inputs. The first input is the name of a variable (so will usually have quotes (") in front of it), and the second input is the value you want to store in that variable.
In primer3, make stores the output of readword in the variable name. (The Logo operation readword outputs a word that the user types at the keyboard.)
Finally, the instruction local "name tells Logo to create a variable named name that is local to procedure primer3. If we do not specify that a variable is local to the procedure, Logo assumes it is a global variable, something we usually don't want.
Use make to write a procedure that asks the user to input two numbers, one at a time, and then outputs or displays the sum of those numbers. (Which do you think is more appropriate here, output or print?)
If you finish early, you might write a program that plays a "Mad Libs" like game with the user:
? madlibs Type a verb and hit enter. flee To flee or not to flee, that is the question.When you wrote your procedure, were the variables you used local to your procedure or were they global variables? How do you know?
Below is a test procedure that illustrates the difference between using make with a local variable and with a global variable.
to testmake local "localvar make "localvar [This is a local variable.] make "globalvar [This is a global variable.] endAssuming you have not already defined a global variable named globalvar, you'll get the following effect when you run testmake:
? print :localvar localvar has no value ? print :globalvar globalvar has no value ? testmake ? print :localvar localvar has no value ? print :globalvar This is a global variable.Because we included the instruction local "localvar in procedure testmake, variable localvar is local to procedure testmake. Running procedure testmake doesn't create or affect any global variables named localvar.
On the other hand, we did not tell Logo that globalvar was to be local to procedure testmake. Because of dynamic scope, Logo looked to the parent procedure (command prompt) for a variable named globalvar. Executing the instruction make "globalvar [This is a global variable.] in procedure testmake caused Logo to create a global variable named globalvar and assign it the value [This is a global variable.]
Remember that procedure primer2 expected two inputs: a first and last name. We can create a procedure with more than one local variable by repeating the local command:
to primer4 local "name local "firstname local "lastname print [What is your name?] make "name readlist ; This stores the *whole* name make "firstname first :name ; This gets and stores the first name make "lastname last :name ; This gets and stores the last name print (sentence [A student named ] :firstname [took a class on Logo.]) print (sentence [The teacher said hey ] :lastname [and helped to make the~ code go.]) endSpend a few minutes trying to rewrite the primer2 procedure so that it uses readlist and does not use make.