knitr::opts_chunk$set(echo = TRUE) library(froth, quietly = TRUE)
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:
dup
duplicates the top element of the stack2
pushes a 2 onto the stack=
pops the top two values and pushes TRUE
if they're equal and FALSE
otherwiseif
checks if the top of stack is TRUE
; if not, it skips to then
." xxx"
prints xxx
then
signals the end of the if
statementThus, 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.
dup
duplicates the number10 <
pushes TRUE
if the number less than 10 and FALSE
otherwiseTRUE
on the stack, print "Small" and go to (8)dup
duplicates the number20 <
pushes TRUE
if the number less than 20 and FALSE
otherwiseTRUE
on the stack, print "Medium" and go to (8)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 expectif
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.
Just like in other programming languages, froth
supports a number of logical operators.
AND
: push TRUE
if the top two elements are both TRUE
OR
: push TRUE
if at least one of the top two elements are TRUE
XOR
: push TRUE
if exactly one of the top two elements is TRUE
NOT
: push TRUE
if the top element is FALSE
and vice-versaSome 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.
if
: if top of stack is TRUE
, executes. Else jumps to the next else
or then
block.else
: executes commands until then
only if the preceding if
did not execute.then
: terminates an if
or if...else
block.\
: 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
: push TRUE
if the top two elements are both TRUE
OR
: push TRUE
if at least one of the top two elements are TRUE
XOR
: push TRUE
if exactly one of the top two elements is TRUE
NOT
: push TRUE
if the top element is FALSE
and vice-versa?DUP
: duplicate top value if it is nonzeroABORT"
: abort if top value true, print error message (terminated by "
)Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.