Control the program flow.
This section describes various commands to control the program flow. The
IF command implements
branching, and various loop commands implement looping.
THROW implement a
mechanism to pass control across procedure boundaries.
Applies a parameter list to a procedure.
APPLY procedure list
APPLY runs the procedure or primitive given as its first input with the arguments supplied as the second input. The output of APPLY is the output of the operation.
Catches runtime errors and THROWn data.
CATCH word instructions CATCH TRUE instructions CATCH "ERROR instructions
CATCH runs the instructions in its second input. If Logo executes a
during the execution of the commands, Logo returns control to the command following the
CATCH command if the input to
THROW matches the word supplied as the first input.
If the thrown word does not match, Logo searches for another CATCH command further up in
the list of called procedures until a match is found, and returns control to the command
following that CATCH command. The CATCH command is used to program procedure exits that
span multiple nested procedure calls. If a thrown word is not caught, Logo treats it as
a runtime error. The instruction list can contain another CATCH command. This way, multiple
CATCH commands can be nested to catch different conditions.
There are a few special uses of CATCH. If the first input to CATCH is TRUE, any error that a procedure throws will be caught. Also, CATCH “ERROR catches an error that would otherwise print a Logo message and return to toplevel. CATCH “TOPLEVEL catches any attempt of the program to return to toplevel.
After catching an error or a thrown word, the built-in variable
a word that describes the caught error. The built-in variable
the error message that Logo would have printed.
TO NAMEIT ; catch the NAMEIT1 value thrown inside NAMEIT1 CATCH "NOTNAME [NAMEIT1] END TO NAMEIT1 PRINT [PLEASE ENTER A NAME] LOCAL"NAME MAKE "NAME READ ; throw the value NOTNAME in case of the input being a list IF NOT WORD? :NAME THEN THROW "NOTNAME PRINT SE :NAME [IS A GOOD NAME] END NAMEIT
Copies a procedure definition.
COPYDEF newname currentname
COPYDEF copies the definition of its second input to its first input. The second input to COPYDEF must be a name of either a procedure or a primitive. Primitives cannot be redefined. Note that when you use COPYDEF with a command, its abbreviation is NOT affected.
Defines a procedure.
DEFINE name instructionlist
DEFINE creates a new procedure with the name of its first input. The second input to DEFINE
determines the definition of the procedure. Any variables for the title line must be in a
list that is the first element of the list of instructions, with no dots (:) before their
names. If there are no variables, the first element must be the empty list. Each remaining
element in the list of instructions is a list that consists of one line of the procedure definition.
The list of instructions is written in the same form as the output of
not be included in the list of instructions, as it is not part of the definition.
Starts the ELSE branch of an IF command.
IF expression THEN instructions ELSE instructions
Ends a procedure definition.
END ends the definition of a Logo procedure. It checks for any open brackets
and reports an error if there are lists which are not closed correctly. END
is used in Logo source files only. Do not use END when defining a procedure
DEFINE command. END is a special word like
ELSE and not a procedure by itself.
Runs a list and collects all outputs.
EVAL runs its input as if it were typed in directly. EVAL does not throw an error
when the execution of the list yields a result; instead, all results are concatenated
into a list and output by the procedure. See also
Runs a list for a defined number of times.
FOR variable-name start-value end-value [runlist] (FOR variable-name start-value end-value [runlist] increment-value)
FOR allows you to execute a list of Logo commands a given number of times. Inputs to FOR are a control variable, a beginning value, an ending value, and a list of Logo commands to be executed. FOR assigns the beginning value to the variable, executes the instruction list, and then increments the variable by one. This process is repeated until the value of the variable is beyond the ending value. The variable increment step can be changed to a number other than one.
FOR expects the name of the variable, the beginning value, and the ending value as three separate input. If a different increment than 1 is desired, that value is an optional fifth input.
The loop variable is created at toplevel if it is not found. Logo sets the loop variable to the next value at the end of each iteration.
If a procedure alters the value during an iteration, the value is overwritten. It is, for example, not possible to terminate a loop by setting the loop variable to the end value.
Runs a list for each element of its first input.
FOREACH word-or-list runlist
The FOREACH command runs a list of commands repeatedly. FOREACH sets an internal pointer to the first element of the list given as its first input. On each run, it substitutes all occurrences of a single question mark ? in the runlist with the list element that the internal pointer points to, runs the runlist, and advances the internal pointer to the next list element. If the runlist reports a value, FOREACH stops and reports that value. If the question mark is quoted as in ”?, the list element is quoted as well; the same applies if the question mark has a leading colon as in :?. If the first input is a word, FOREACH runs the list for each character of the word.
If the first input is a word, FOREACH runs the list for each of the word's characters.
FOREACH substitutes question marks inside sub-lists. Therefore, nested FOREACH loops are not impossible. If you need nested FOREACH loops, you need to create a separate procdure for the inner FOREACH loop and call that procedure from the outer FOREACH loop.
Note that FOREACH is different from the FOREACH command of Berkeley Logo. The Berkeley Logo FOREACH command knows the ?REST symbol as well as the # symbol; Logo does not recognize these symbols. Also, Berkeley Logo does not transfer a quote or a colon from the question mark to the replaced symbol like Logo does.
Runs a list forever.
Jumps to a label inside a procedure.
GO transfers the flow within a procedure to the command immediately following its corresponding
LABEL command. GO and its corresponding
LABEL must reside within the same procedure, and they must reside within the same runlist. A GO from the body of a procedure to, for example, the runlist of an
IF command is not possible.
The procedure PINWHEEL runs forever; click the Stop button to stop the procedure.
TO PINWHEEL FD 100 LABEL "LOOP REPEAT 4 [FD 50 RT 90] RT 20 GO "LOOP END PINWHEEL
Runs instructions based on a condition.
IF expression [then-instructions] IF expression [then-instructions] [else-instructions] IF expression then-instructions IF expression THEN instructions IF expression THEN instructions ELSE instructions
IF checks its first input for being TRUE or FALSE. If the value is TRUE, it runs or outputs its second input, and if the value if FALSE, it runs or outputs its third input. If the second or third inputs are lists, IF treats these inputs as instruction lists, and runs the input.
There are several ways to specify the inputs to IF. If other commands just follow the IF command,
all commands are executed only if the condition is true. Optionally, the list of commands
may be preceded by the
THEN keyword. If the list of commands contains the keyword
ELSE, the executions of commands stop at that keyword if the condition is true, and the
remainder of the line is skipped. If the condition is false, all commands up to and including
ELSE keyword is skipped, and execution continues at the command behind
If the command following the condition is a list, the list is considered to be a runlist, and
Logo executes that list if the condition is true, and continues execution at the command behind
the list. If that command also is a list, however, that list is considered to be a runlist that
is executed if the condition is false.
Runs a list if TEST was false.
IFFALSE runs its first input if the most recent
TEST operation is FALSE. If its
input is a list, IFFALSE treats it as an instruction list, and runs the input. If the
TEST operation is TRUE, IFFALSE does nothing.
TO GUESS.IT :NUM PR [CAN YOU GUESS MY NUMBER?] MAKE "GUESS READWORD TEST :NUM = :GUESS IFTRUE [PR [GOOD GUESS!] STOP] IFFALSE [PR [NO, TRY AGAIN.]] GUESS.IT :NUM END GUESS.IT 4
Runs a list if TEST was true.
IFTRUE runs its first input if the most recent
TEST operation is TRUE. If its
input is a list, IFTRUE treats it as an instruction list, and runs the input.
TEST operation is FALSE, IFTRUE does nothing.
TO GUESS.IT :NUM PR [CAN YOU GUESS MY NUMBER?] MAKE "GUESS READWORD TEST :NUM = :GUESS IFTRUE [PR [GOOD GUESS!] STOP] IFFALSE [PR [NO, TRY AGAIN.]] GUESS.IT :NUM END GUESS.IT 8
Ignores the output of a procedure.
IGNORE simply “swallows” any output created by its input, which can be any Logo object. IGNORE is very handy if the output of any procedure is not needed.
Marks a target for the GO command.
LABEL marks the target of a GO-LABEL loop. Its input must match the input of the corresponding GO command.
LABEL is used in conjunction with
The procedure PINWHEEL runs forever; click the Stop button to stop the procedure.
TO PINWHEEL FD 100 LABEL "LOOP REPEAT 4 [FD 50 RT 90] RT 20 GO "LOOP END PINWHEEL
Declares local variables inside a procedure.
LOCAL name (LOCAL name1 name2 ...)
LOCAL defines its input as a local variable whose value affects only the procedure in which it is called. The variable's previous value (if any) is saved at the beginning of the procedure where it is redefined and restored at the end of the procedure. The variable is only available within the procedure in which it is defined and in all other procedures which are called from within the procedure where the variable is defined. The inputs to LOCAL must be quoted words.
Initially, a local name does not have a value. An attempt to read from a freshly declared local name causes a runtime error.
Exits a procedure and outputs a value.
OUTPUT makes its input the output of the procedure. After OUTPUT is run, control returns to the calling procedure or to toplevel. If OUTPUT is used outside of a procedure, control returns to toplevel, and the result of the current toplevel command is OUTPUT's input.
Reports the value of the REPEAT counter.
Runs a runlist repeatedly.
REPEAT number list
REPEAT runs the list of instructions in the second input the number of times indicated by its first input. The number input to REPEAT can be any positive integer greater than 0. If the number is not an integer, its fractional portion is ignored. REPEAT commands can be nested, or placed inside other REPEAT commands.
REPEAT 5 [PRINT [I WILL NOT BITE MY NAILS]] I WILL NOT BITE MY NAILS I WILL NOT BITE MY NAILS I WILL NOT BITE MY NAILS I WILL NOT BITE MY NAILS I WILL NOT BITE MY NAILS
Reports the total number of REPEATs.
REPTOTAL outputs the total number of repetitions of the innermost
FOREVER command. If there is no active
FOREVER command, REPTOTAL outputs the value -1. In case of
REPTOTAL outputs a very large number.
Runs a word or list.
RUN runs its input as if it were typed in directly. RUN outputs whatever its
list of instructions reports. If the run list contains more than one command,
and one of the commands outputs a value, RUN does not run the remaining commands.
If the input to RUN is a word, RUN outputs that word.
Exits a procedure.
STOP causes Logo to halt execution of the current procedure and return to the calling procedure.
If there is no calling procedure, Logo returns to
Test a condition; used with IFTRUE and IFFALSE.
TEST determines whether its input is TRUE or FALSE and stores it for later use by
IFFALSE. The effect of TEST is local
to the procedure in which it is used; any corresponding
IFFALSE must be in the same procedure or a subprocedure. If no procedure
is active, the result of the TEST is stored globally, and any procedures that
are called afterwards inherit this value.
TO GUESS.IT :NUM PR [CAN YOU GUESS MY NUMBER?] MAKE "GUESS READWORD TEST :NUM = :GUESS IFTRUE [PR [GOOD GUESS!] STOP] IFFALSE [PR [NO, TRY AGAIN.]] GUESS.IT :NUM END GUESS.IT 5
Outputs a procedure definition.
TEXT takes a quoted procedure name as input and reports the definition of that procedure.
The form of the output is a list. The first element of the list is any variable(s) defined
in the title line of the procedure. If there are no variables, the first element is the
empty list (). Each remaining element is a list that consists of one line of the procedure
definition. The output of TEXT is in the same form as the required input for
If the input to TEXT is a primitive, TEXT output the list [Primitive XXX], where XXX is the
name of the primitive.
Starts the THEN branch of an IF command.
IF expression THEN instructions IF expression THEN instructions ELSE instructions
THEN starts the branch of an
IF command that is executed if the condition is true.
THEN collects the entire remainder of the current line into a list and outputs a list unless
it finds an
ELSE command; if found, THEN stops collecting at the ELSE command.
THEN is a special word like
END and not a procedure by itself.
Throws a Logo word or a runtime error.
THROW word (THROW runtime-error-word text) (THROW)
THROW returns control to the
CATCH statement with a matching first input, or to the CATCH TRUE
statement, whichever comes first in the chain of active procedures. If THROW is used without inputs,
it re-throws an error that was caught with a
CATCH statement in the same procedure. If there was
no caught error, (THROW) does nothing. The command THROW “TOPLEVEL ends all programs and returns control to
the Listener if the error is not caught.
If THROW is executed with more than one input, it throws a Logo runtime error.
:ERROR for a list
of predefined Logo runtime error types. You are free to throw whatever you like, though.
Print an error if present, and rethrow that error.
TO RETHROW :RUNLIST CATCH "ERROR :RUNLIST IF WORD? :ERROR [PR :ERRORTEXT] ; print error if present (THROW) ; rethrow the error END RETHROW [SQRT -1]
Defines a procedure.
TO procname TO procname :input ... TO procname ... [:optional-input value] ... argcount TO procname ... [:list-input] argcount
TO is the first word of a procedure definition. When typed at toplevel and followed by an unquoted procedure name, the prompt changes to the procedure name as lines are typed in. A single line containing the word END ends the procedure definition.
The input to the procedure follows the procedure name. Each input is a colon, followed by the name of the input variable. It is possible to define inputs with default values. These input variables are preset with the given value if the procedure is called with too few inputs. An optional input is a two-element list. The first element is a colon, followed by the name of the input variable, and the second element is the default value. Also, the last input may be a single-element list containing a colon, followed by the input variable name. Such an input variable collects all additional inputs into a list and assigns this list to the input variable. If there are too few inputs, the variable is set to the empty list.
Note: The value for the optional input is not evaluated. It cannot be an expression, and
quoted values remain quoted. Future versions of Logo will be able to evaluate an expression; if you want to stay compatible with future versions of Logo, please use only the values
FALSE, numbers, or lists; do not use words, as they may be interpreted as procedure names in the future.
It is possible to define the default number of inputs. This number is the number of inputs that Logo feeds the procedure with if the procedure call is not enclosed in parentheses. The number is given as the last element of the TO command. It must always be equal to or greater than the number of non-list inputs. If there is no number given, the number of inputs amounts to the number of inputs that are not lists.
The command TO FUNC :ONE [:TWO 2] 1 defines, for example, the procedure FUNC, with one required and one optional input. If the call is not enclosed in parentheses, Logo will call the procedure with one input, and set the input :TWO to the value 2. Otherwise, Logo will send :TWO to the second input. Thus, FUNC 123 would set :ONE to 123, and :TWO to 2, but (FUNC 123 456) would set :TWO to 456.
If, for example, the command is TO FUNC [:ARGS] 2, Logo usually calls FUNC with two inputs. Both inputs are concatenated into a list and assigned to the variable :LIST. Using the command FUNC “A “B sets :LIST to [A B]; using (FUNC 1 2 3) sets :LIST to [1 2 3], and (FUNC) sets :LIST to the empty list.
TO FUNC :A [:B 2] 1 OP LIST :A :B END FUNC 11 (FUNC 11 22) TO FUNC [:LIST] 1 OP :LIST END FUNC 11 (FUNC 11 22)
Returns to toplevel.
TOPLEVEL stops execution of a procedure and returns Logo to toplevel, the command mode.
TOPLEVEL in a procedure performs the same function as clicking the Stop button. You may
THROW “TOPLEVEL to return to toplevel. TOPLEVEL may also be caught with a
CATCH command. Note that TOPLEVEL is different from
STOP in that control
is not returned to any calling procedure.
Waits for a number of milliseconds.
WAIT inserts a pause before the next instruction is run. The length of the pause is the input to WAIT times 1/1000 of a second (milliseconds).
If you use the command WAIT -1, Logo never stops waiting. This is convenient for programs that handle events, because you do not want the program to end and lose its
The accuracy of WAIT depends on the wait time and the number of executing background procedures. A WAIT time of under 15 is usually quite precise, while longer WAIT times may wait longer than expected. WAIT times under 15 do not release the CPU, while longer wait times do.
; start InO-Bot and turn off motors for a second if the infrared ; sensor input value is > 0.9 WHEN [INOBOT INFRARED > 0.9] [ MOTORS 0 WAIT 1000 MOTORS 0.3 ] MOTORS 0.3 WAIT -1
Runs a list until a condition is false.
WHILE testlist runlist
WHILE evaluates its first input and runs the Logo command(s) in its second input if the value of the first input is TRUE. WHILE will continue this process until the value of the first input is FALSE.
MAKE "X 1 WHILE [:X <= 5] [PRINT :X MAKE "X :X + 1] 1 2 3 4 5