Several looping constructs are provided.
For compatibility with older systems, wherever the word DO is used in the examples below, the word THEN is also accepted. Similarly most looping constructs will accept CLOSE or ENDDO as the closing bracket, for consistency with POP-2 and earlier versions of Pop-11. It is probably best to ignore these variant forms, as they may be withdrawn later.
The examples of looping constructs below are among the most widely used ones. There are others described in HELP LOOPS and HELP FOR. Moreover, because Pop-11 is an extendable language, users can define new syntax words and macros defining new constructs, as explained below. Examples are the library definitions of "foreach", "forevery", and "switchon", each of which has its own help file. In each case the library definitions can be inspected using the "showlib" command, e.g.
ENTER showlib foreach
This means, check if the <condition> is true, and if not then do the action. Then test again to see if the condition is true. And so on. The condition is tested again each time AFTER <action> is done. For example, to print out all the numbers from 3 to 99 do:
vars num; 3 -> num; until num > 99 do num => num + 1 -> num; enduntil;The <action> element of a loop (like a conditional) may be an arbitrarily complex pop-11 imperative, or sequence of imperatives. So to print out the words "THE" "CAT" "SAT" "ON" "THE" "MAT", you could make a list of the words, then keep printing out elements of the list. We use the system procedure TL which, when given a list, returns a new list containing all except the first element of the original. chop one off. until the list is [], thus:
vars list; [the cat sat on the mat ] -> list; until list == [] do list(1) => ;;; print first element tl(list) -> list; ;;; prepare for next enduntil;NB the loop will not be terminated immediately if the condition becomes TRUE in the middle of executing the action. Note also that the condition is always tested at least once BEFORE anything else is done.
After the word REPEAT you can have a number, e.g. 4, or a variable whose value is a number, e.g. REPEAT N TIMES... or a more complex expression which calculates a number,
e.g. repeat 66 + 53 times.... endrepeat;The <action> will be done the specified number of times.
Example: to print out 10 blank lines, do
repeat 10 times pr(newline) endrepeat;Make a list of 10 randomly generate numbers between 1 and 20
[% repeat 10 times random(20) endrepeat %] => ** [12 15 19 18 9 5 4 11 17 19]See also the definition of procedure SQUARE, above.
For indefinite iteration do
REPEAT <action> ENDREPEAT;e.g.
repeat [you are wonderful] => endrepeat;You will need to interrupt (e.g. with CTRL-C).
(See HELP LOOPS for more on interrupting loops)
This means, test the condition. If it is true, then do the action. Then test the condition again. And so on. This is similar to UNTIL, except that WHILE does the action each time the condition is found to be TRUE whereas UNTIL does the action each time the condition is found to be FALSE. In both cases the condition is tested first.
E.g. to find the first integer whose square is greater than 1000, you could do:
vars num; 1 -> num; while num * num < 1000 do num + 1 -> num endwhile;The value of num and its square can now be printed out:
num => ** 32 num * num => ** 1024
We have seen examples of the use of the `for ... endfor' construction, to iterate over lists. In fact there are several different formats.
The following is a very general for loop, which can be used in many contexts, although a more specific version will often be preferred.
FOR <initiate> STEP <step> TILL <condition> DO <action> ENDFOR;This is equivalent to:
<initiate>; UNTIL <condition> DO <action>; <step> ENDUNTIL;In other words, do the initialisation, then, until the condition evaluates to TRUE, repeatedly do the action followed by the step.
For example, to print out all the numbers from LO to HI, separated by spaces:
for lo-> x step x+1 -> x till x > hi do spr(x); endfor;N.B. The `step' is not done until after the `action'.
Suppose FOO is a procedure of two arguments, a word and a number. If you are given a list of words and a list of numbers and wish to apply FOO to the first element of each, then the second element of each, etc., until either there are no more words, or no more numbers, you could do something like:
vars w, n; for words -> w; numbers -> n; step tl(w) -> w; tl(n) -> n; till w = [] or n = [] do foo(hd(w), hd(n)); endfor;________________________________________________________________
X will take on as its value the first element of LIST, then the second element, then the third, etc. Each time the <action> is performed the latest value of X will be used. E.g. printing out the squares of a list of numbers
for num in numbers do pr('\nThe square of: '); pr(num); pr(' is: '); pr(num*num); endfor;(Note: this uses strings. `
\
n' in a string causes a new line to be
printed.)
It is also possible to iterate over several lists at the same time, e.g.
for x1, x2, x3, in list1, list2, list3 do <something involving x1, x2, x3> endfor;________________________________________________________________
Here, the first time the <action> is done L will refer to the whole LIST. The second time it will refer to the TAIL of the list (i.e. a list of all but the first element). The next time a still shorter list, and so on. E.g.
for l on [a b c] do l=> endfor; ** [a b c] ** [b c] ** [c]Again this can be done with several lists at once.
________________________________________________________________
FOR X FROM <number> BY <number> TO <number> DO <action> ENDFOR;
e.g. to print out numbers from 2 to 20 going up in steps of 7
for x from 2 by 7 to 20 do x => endfor; ** 2 ** 9 ** 16or going down:
for x from 50 by -12.5 to -20 do x => endfor; ** 50 ** 37.5 ** 25.0 ** 12.5 ** 0.0 ** -12.5the `FROM <number>' and `BY <number>' portions can be omitted. The starting value defaults to 1, as does the increment.
vars x; for x to 6 do pr(x); pr(space) endfor; 1 2 3 4 5 6
All the <conditions> in what follows should be expressions which evaluate to TRUE or FALSE.
(1) IF <condition> THEN <action> ENDIF; (2) IF <condition> THEN <action1> ELSE <action2> ENDIF; if the <condition> is true, then <action1> will be executed, otherwise <action2> will be executed. (3) IF <condition1> THEN <action1> ELSEIF <condition2> THEN <action2> ELSEIF <condition3> THEN <action3> ELSEUNLESS <condition4> THEN <action4> ............. ............. ELSE <default action> ENDIF;This `multi-branch' conditional says:
try <condition1> then <condition2> etc in turn until an ELSEIF condition is found which is TRUE, or an ELSEUNLESS condition is found which is FALSE. If either is found, execute the corresponding <action>. If none of the conditions comes out TRUE then do the thing following ELSE, i.e. <default action>.Note that in an imperative you do not have to have the ELSE <default action> bit. You must, however, have it in an expression intended to denote, something, for then it should denote something under all conditions. You can include as many ELSEIF clauses as you like.
(4) UNLESS <condition> THEN <action> ENDUNLESS; this is equivalent to: IF NOT(<condition>) THEN <action> ENDIF;UNLESS can also have ELSEUNLESS and ELSEIF and ELSE clauses.
Note: the words NOT, AND and OR are available for use in formulating complex conditions. E.g.
IF <condition1> OR (<condition2> AND NOT(<condition3>))
To test whether the value of X is bigger than the value of Y, and print out the bigger value do:
if x > y then x => else y => endif;Compare:
if x > y then x => elseif y > x then y => else "same" => endif; if 2 < x and x < 6 then true else false endif =>Note that the last example is exactly equivalent to:
2 < x and x < 6 =>If LIST1 and LIST2 are two lists and you want to print out the one which is shorter you could do:
if length(list1) < length(list2) then list1 else list2 endif =>If N and M are two numbers, and you wish to assign the bigger one to the variable MAX then do:
if m > n then m else n endif -> max;