if
Most programming languages offer two basic ways of altering the normal left-to-right, top-to-bottom code execution sequence: a way of looping repeatedly over a section of code, and a way of executing a section of code only if some condition is true.
We've seen a way to execute code repeatedly, using
for
; Let's look at a way to execute code
conditionally, using if
:
Stack: : flip frandom 0.5 > if "heads!\n" else "tails!\n" fi , ; Stack: flip tails! Stack: flip tails! Stack: flip heads! Stack: flip tails! Stack: flip heads! Stack:
How does this work? Well, it introduces several new
functions. One is frandom
, a function which returns a
randomly selected number between 0.0 and 1.0:
Stack: frandom frandom frandom frandom Stack: 0.00176691 0.187589 0.990434 0.750497 pop pop pop pop frandom frandom frandom frandom Stack: 0.366273 0.351209 0.573344 0.132554 pop pop pop pop frandom frandom frandom frandom Stack: 0.0641664 0.950853 0.15356 0.584649
Another is >
, a function which returns a true
value
if its first argument is greater than the second, else
a false
value. What is a false
value in MUF?
The special constant nil
. What is a true
value in
MUF? Any but nil
!
Stack: 1 2 > Stack: nil pop 2 1 > Stack: t
You can compare strings as well as numbers with >
:
Stack: "alpha" "beta" > Stack: nil pop "beta" "alpha" > Stack: t
And, as you might expect, MUF has the full usual set of comparison functions:
!= Not-equal < Less-than <= Less-than-or-equal-to = Equal-to > Greater-than >= Greater-than-or-equal-to
Notice that it looks a little odd to write "1 2 >" instead
of "1 > 2" the way Ms Grundy did in third grade, but that
this order is required by our strict rule of evaluating
words left-to-right: >
cannot execute until we have
pushed both of its operands on the stack for it.
(We could make special exceptions from left-to-right evaluation order just for comparison functions, but then MUF would start getting more complicated than we want, and become a quite different sort of language. There is nothing wrong with building more complicated languages designed to look more like what Ms Grundy taught in school, and Muq will eventually have such languages as well as MUF, but for now let's stick to our simple-minded little language.)
With that background in mind, let's take another look
at our flip
function:
: flip random 0.5 > if "heads!\n" else "tails!\n" fi , ;
The "random 0.5 >" will leave a true
value on the
stack half the time, and a false
value (nil
)
on the stack the other half of the time. What does the
if
do?
In MUF, if
pops one value off the stack and
looks at it. If that value is true
(anything but
nil
), all the words from if
to else
are
executed. If that value is false
(nil
), all
the words from else
to fi
are executed.
(fi
, as you might guess, is just if
backwards,
and serves to mark the end of the statement.)
In function flip
, this means that the
if-else-fi
pops a true/false value off the stack, and
then pushes either "heads!\n" or "tails!\n" on the stack, to
get printed by the final comma function.
Again, it looks peculiar to put the true/false value
controlling the if
before the if
, but
that order is forced by our simple-minded left-to-right
evaluation rule: if
cannot make its decision until we
give it the information it needs.
You may wish to experiment interactively with if
for
awhile, until it begins to feel natural:
Stack: nil if "Yup!" else "Nope!" fi Stack: "Nope!" pop t if "Yup!" else "Nope!" fi Stack: "Yup!" pop 2.3 if "Yup!" else "Nope!" fi Stack: "Yup!"
Believe it or not, you've now mastered most of the essentials of elementary MUF programming! In principle, you now know enough MUF to compute anything which can be computed.
Let's finish off by covering a few very handy and frequently used facilities.
Go to the first, previous, next, last section, table of contents.