Go to the first, previous, next, last section, table of contents.


Fun With Loops

Let's reconsider our function to print four lines:

: print-4-lines "Line1!\n" , "Line2!\n" , "Line3!\n" , "Line4!\n" , ;

This is a rather repetitious way to print four lines, and defining function to print a thousand or a million lines that way would be ridiculous. We'd like to have a way to tell MUF to do something lots of times without actually having to list it that many times.

The for loop is one way to do this. (As we'll see, MUF has lots of different loops, each designed to simplify programming some particular kind of repetitive task. We'll also see that MUF lets us define new kinds of loops ourself if we want to -- something most programming languages don't allow.) Here's a new function to print four lines:

Stack:
: print-4 for i from 0 upto 3 do{ "Line!\n" , } ;
Stack:
print-4
Line!
Line!
Line!
Line!
Stack:

How does this work? MUF runs the code between the do{ and the } four times, with the variable i set successively to the values 0,1,2,3. MUF starts it at the first number given and keeps incrementing it by one until it is equal to the second number given.)

Unlike Forth, MUF doesn't restrict loops to living only inside of words: It can be fun to execute them directly from the commandline:

Stack:
for i from 0 upto 3 do{ "Line!\n" , }
Line!
Line!
Line!
Line!
Stack:
for j from 2 upto 4 do{ "Line!\n" , }
Line!
Line!
Line!
Stack:

You're wondering about those i and j variables, right? A variable is just a name for a quantity or object or string or whatever. When you mention a variable by name, MUF silently replaces the variable by the corresponding value. MUF has two major types of variables, and we'll discuss them shortly. In the meantime, let's try an experiment:

Stack:
for i from 0 upto 19 do{ i }
Stack: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

What happened here? As instructed, MUF executed the code from do{ to } twenty times, with the variable i successively given the values zero to nineteen. The repeated code consisted only of the variable i: Each time it encountered the variable, MUF replaced it by its value and then, since we didn't tell it anything else to do with the value, MUF does what it always does in such a situation: It made a neat little pile of the values.

Possibly you are not looking forward to doing pop twenty times to get rid of all those values? Use another loop:

Stack: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
for i from 0 to 19 do{ pop }
Stack:

Whee!

If we had a way to count how many items there are on the stack, we could write a general function to clear the stack. It just happens that MUF has such a function, called depth:

Stack:
"alpha" "beta" "gamma"
Stack: "alpha" "beta" "gamma"
depth
Stack: "alpha" "beta" "gamma" 3

Here is a pop-all function that will pop all the items on the stack. In this example we use the keyword below instead of the keyword upto: The difference is that below stops just before reaching the upper limit, while upto stops only after reaching the upper limit. (The "depth -> limit" notation for assigning a value depth to a local variable limit will be explained in the next section, Fun With Variables.)

Stack:
: pop-all   depth -> limit   for i from 1 upto limit do{ pop } ;
Stack:
for xx from 40 below 56 do{ xx }
Stack: 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
pop-all
Stack:

Let's close this section by showing a function which will print any number of lines, and number them as well, nicely generalizing the print-4-lines function which we began with. This uses the ]print function, which we've not covered yet, but the general idea should be clear:

Stack:
: print-n-lines -> k for i from 0 below k do{ [ "Line %d!\n" i | ]print , } ;
Stack:
4 print-n-lines
Line 0!
Line 1!
Line 2!
Line 3!
Stack:
2 print-n-lines
Line 0!
Line 1!

How does this work? print-n-lines finds a number on the stack -- 4 or 2 in the above two examples. It slips a zero underneath the number via "0 swap" to make a valid iteration range for for. It then constructs the actual string to print via the "[ ... ]print" magic (notice the reference to i slipped in there), and prints the string with the comma. Simple?

You can play with ]print a bit if you want:

Stack:
[ "->%d<-" 12 | ]print
Stack: "->12<-"
pop
Stack:
[ "->%d<-->%g<-" 12 3.5 | ]print
Stack: "->12<-->3.5<-"

The ]print function is a neat way of building all sorts of strings, but we need to explain blocks before we can explain it properly!

Does anyone remember when the phone company supplied the time for free?

Stack:
for sec from 10 upto 50 by 10 do{
    "At the tone the time will be " ,
    time , " and " , sec , " seconds...\n" ,
    10 sleepJob
    "BEEP!\n" ,
}
At the tone the time will be  4:57AM and 10 seconds...
BEEP!
At the tone the time will be  4:57AM and 20 seconds...
BEEP!
At the tone the time will be  4:57AM and 30 seconds...
BEEP!
At the tone the time will be  4:57AM and 40 seconds...
BEEP!
At the tone the time will be  4:57AM and 50 seconds...
BEEP!
Stack:

(Yes, I was a bad boy again and used some functions which we haven't officially been introduced to yet. Forget you saw any of that, ok? grin)


Go to the first, previous, next, last section, table of contents.