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.