A major component of computers is being able to make decisions. If
you’ve worked with other programming languages, you’ll be familiar with
common terms like if and else.
Let’s look at a quick example to introduce conditionals:
fr> : IS_TWO? ( n -- n ) dup 2 = if ." It's two!" then ;
ok.
fr> 2 is_two?
It's two! ok.
The complete definition is dup 2 = if ." xxx" then. We
have a few new words we haven’t seen before here, so lets step through
this definition:
-
dupduplicates the top element of the stack -
2pushes a 2 onto the stack =pops the top two values and pushesTRUEif they’re equal andFALSEotherwiseifchecks if the top of stack isTRUE; if not, it skips tothen-
." xxx"printsxxx -
thensignals the end of theifstatement
Thus, we get the following behavior:
fr> 2 is_two?
It's two! ok.
fr> 1 is_two?
ok.
Note how in the second case, we have no output, since the value
pushed is not equal to 2. It would be nice to have some output to tell
us this, which is where else comes in. else
executes statements only if the if branch did not execute.
For example:
fr> : IS_TWO? ( n -- n ) dup 2 = if ." It's two!" else ." Not two :(" then ;
ok.
fr> 2 is_two?
It's two! ok.
fr> 1 is_two?
Not two :( ok.
then statements end the conditional. It’s important to
note that everything after then will execute regardless
of whether the if block executed or not. You
must include a then to close an if
statement, or else the interpreter won’t know where to skip to after the
end of interpretation.
We can also nest if statements. For this example, we’ll
use <, which functions exactly like =
except that it pushes TRUE if a < b and
FALSE otherwise.
fr> : is_big? ( a -- a ) dup 10 < if ." Small" else dup 20 < if ." Medium" else ." Big" then then ." number" cr ;
ok.
fr> 5 is_big?
Small number
ok.
fr> 15 is_big?
Medium number
ok.
fr> 25 is_big?
Big number
ok.
Writing long functions like this can be a little annoying. We can use
the \ to break up lines without executing functions, which
can help make them more readable:
fr> : is_big? ( a -- a ) \
+ dup 10 < \
+ if \
+ ." Small" \
+ else dup 20 < \
+ if ." Medium" \
+ else ." Big" \
+ then \
+ then \
+ ." number" ;
ok.
The interpreter will add the + to signify that it’s
waiting for you to finish the line. If you get stuck, use
CTRL+C to quit.
So what is happening here? It’s a function that expects a number on the stack and doesn’t consume it.
-
dupduplicates the number -
10 <pushesTRUEif the number less than 10 andFALSEotherwise - if
TRUEon the stack, print “Small” and go to (8) -
dupduplicates the number -
20 <pushesTRUEif the number less than 20 andFALSEotherwise - if
TRUEon the stack, print “Medium” and go to (8) - print “Big”
- print “number”
Note: Every if needs exactly one
then!
There are many comparators available, not just = and
<:
-
=: are the top two elements equal? -
<: is the top element greater than the first? -
>: is the top element less than the first? -
<>: are the top two elements not equal? -
0=: is the top element zero? -
0<: is the top element greater than zero? -
0>: is the top element less than zero? -
<=,>=are defined as one would expect
if uses R’s as.logical to check if the top
value evaluates to TRUE. This means that nonzero numbers
will be treated as TRUE, whereas 0 will
evaluate to false. Things that cannot be converted to logicals
(e.g. 'a') will throw an error.
Logical Operators
Just like in other programming languages, froth supports
a number of logical operators.
-
AND: pushTRUEif the top two elements are bothTRUE -
OR: pushTRUEif at least one of the top two elements areTRUE -
XOR: pushTRUEif exactly one of the top two elements isTRUE -
NOT: pushTRUEif the top element isFALSEand vice-versa
Some words come with built-in checks. For example, ?DUP
duplicates the top value only if it is not zero. For error-handling, you
can use ABORT". ABORT" checks the stack for a
value; if it is TRUE, it clears the stacks and prints an
error message.
Words in this chapter
-
if: if top of stack isTRUE, executes. Else jumps to the nextelseorthenblock. -
else: executes commands untilthenonly if the precedingifdid not execute. -
then: terminates aniforif...elseblock. -
\: signals to the interpreter that you’re making a newline without running commands -
=: are the top two elements equal? -
<: is the top element greater than the first? -
>: is the top element less than the first? -
<>: are the top two elements not equal? -
0=: is the top element zero? -
0<: is the top element greater than zero? -
0>: is the top element less than zero? -
<=: is top element greater than or equal to the second? -
>=: is top element less than or equal to the second? -
AND: pushTRUEif the top two elements are bothTRUE -
OR: pushTRUEif at least one of the top two elements areTRUE -
XOR: pushTRUEif exactly one of the top two elements isTRUE -
NOT: pushTRUEif the top element isFALSEand vice-versa -
?DUP: duplicate top value if it is nonzero -
ABORT": abort if top value true, print error message (terminated by")