COMP203: Lecture 11


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.

Changes for 2011

In the fall of 2011, we spent an extra day on if and ifelse. This brought us out of synch with these notes. In response to a question about the three question quiz problem, Professor Burgiel wrote the following procedure. It demonstrates the use of for, initalization of a variable, and incrementation of that variable using if.
to countthrees :number
 ; A procedure to count the number of multiples of 3 between 1 and its input.
 local "threes
 make "threes 0

 for [i 1 :number] ~
     [if equalp 0 (remainder :i 3) [make "threes :threes+1]]

 print (sentence [There are ] :threes [multiples of 3 between 0 and] word :number ".)
end

Functions of Functions: Finishing Flourishes

Review of for and while

Use for to write a procedure countdown.for that takes one input and counts down from that input to zero:
? countdown.for 8
8
7
6
5
4
3
2
1
Blastoff!
If you have extra time, use while to write a procedure countdown.while that does exactly the same thing as countdown.for.

In general, anything you can do with for you can also do with while. We don't really need the for command, but it's simpler than while and for most purposes for does what we need done.

Evaluation in for controls

On page 78 of Chapter 5 there is a procedure that uses for to take a full name as input and then output a list of initials from that name. This procedure has several interesting features:
to initials.for :name 
 ; code copied from page 78 of Computer Science Logo Style
 local "result
 make "result []
 for [i 1 [count :name]] ~
     [make "result sentence :result first (item :i :name)]
 output :result
end
First, look at the first input to for. Instead of being a list containing a variable name and two (or three) numbers, it contains a variable name, a number, and a list. If you want to compute the values in the first input to for, you must include the operations used to compute the value in square brackets.

In the example above, we compute the number of items in the name. This lets for go through each name in the list and use first to get the first letter from each. In the example below, we compute the square of a number and then count up to the square:

to counttosquare :n
 for [i 1 [:n * :n]] [print :i]
end
If we forget to put the command to be evaluated in a list, we might get an error or we might get some error free but unexpected result. Try out the two procedures below, figure out why they do what they do, then fix the errors in them.
to counttotwice :n
 for [i 1 2 * :n] [print :i]
end

to reverseword :forward
 local "reversed
 make "reversed "
 for [i 1 count :forward] ~
     [make "reversed word item :i :forward :reversed]
 output :reversed
end

Local Variables with for and while

In procedures initials and reverseword above, we used a local variable to store a list of intials or a partially-formed backward word as we went through the for loop. If we were using a for loop to add a list of numbers, we would probably store a running total in a local variable.

to sumlist :numlist
 local "total
 make "total 0

 for [i 0 [count :numlist]] [make "total :total + item :i :numlist]
 output :total
end
There are three key steps here: First, you name a local variable (to avoid creating or changing global variables). Second, you initialize that variable -- you give it a starting value of 0 for a total, [] for a list or " for a word. (If you skip step 2 you will get an error message when you try to add to the variable.) Third, you add initials, numbers or other values to your variable, using make and operations like sentence, word or sum (+).

Creating a local variable and using make to change its value runs counter to the functional programming style that we've been using so far, and is probably the reason the author seems to prefer the operation map to commands like for and while. Different programming techniques are more or less elegant than others. As a programmer you will have to find a balance between elegance, functionality, and expedience in writing your procedures.

Exercise: Write a procedure oddsum that accepts a number n as input and outputs the sum of the first n odd numbers. (E.g. oddsum 3 should output 1 + 3 + 5 = 9.)

map

What is map? It's a Logo operation that requires two inputs. The first input is the name of a Logo operation that requires one input. The second input is a list of items to be input to the procedure named in the first input. The output of map is the result of applying the first input to each item in the second input. For example:
print map "first [Heidi Louise Burgiel]
show map "random [6 6 6 6 6]
show map "not [true false true true]
show map "oddsum [1 2 3 4 5 6]
Procedure map is a wonderful tool for turning old lists into new ones -- read the exercises in Chapter 5 to get some good ideas for experiments. Since Logo is created from lists and designed to handle lists well, it makes sense that Logo has good built-in procedures for working with lists.

Other computer languages have other advantages, and may or may not have nice tools like map. The C programming language is very good at efficiently using a computer's physical memory. Java was designed to work well on many different kinds of computers (including the ones in your car engine and your TIVO). Because you and your students may never need to use a computer language that includes a command like map, I am not spending a lot of time lecturing on it or on the similar commands described in Chapter 5.