:

The Two Kinds of Loops in Maple

Maple

When discussing Maple programming, we often refer to for-loops, while-loops, until-loops, and do-loops (the latter being an infinite loop). But under the hood, Maple has only two kinds of loop, albeit very flexible and powerful ones that can combine the capabilities of any or all of the above, making it possible to write very concise code in a natural way.

Before looking at some actual examples, here is the formal definition of the loops' syntax, expressed in Wirth Syntax Notation, where "|" denotes alternatives, "[...]" denotes an optional part, "(...)" denotes grouping, and Maple keywords are in boldface:

[ for variable ] [ from expression ] [ by expression ] [ to expression ]
[ while condition ]
do
statement-sequence
( end do | until condition )
[ for variable [ , variable ] ] in expression
[ while condition ]
do
statement-sequence
( end do | until condition )

In the first form, every part of the loop syntax is optional, except the do keyword before the body of the loop, and either end do or an until clause after the body. (For those who prefer it, end do can also be written as od.) In the second form, only the in clause is required.

The simplest loop is just:

do
statement-sequence
end do

This will repeat the statement-sequence forever, unless a break or return statement is executed, or an error occurs.

One or two loop termination conditions can be added:

• A while clause can be written before the do, specifying a condition that is tested before each iteration begins. If the condition evaluates to false, the loop ends.
• An until clause can be written instead of the end do, specifying a condition that is tested after each iteration finishes. If the condition evaluates to true, the loop ends.

A so-called for-loop is just a loop to which iteration clauses have been added. These can take one of two forms:

• Any combination of for (with a single variable), from, by, and to clauses. The last three can appear in any order.
• A for clause with one or two variables, followed by an in clause.

The following for-loop executes statement-sequence 10 times:

for i from 1 to 10 do
statement-sequence
end do

However, if the statement-sequence doesn't depend on the value of i, both the for and from clauses can be omitted:

to 10 do
statement-sequence
end do

In this case, Maple supplies an implicit for clause (with an inaccessible internal variable), as well as an implicit "from 1" clause. In fact, all of the clauses are optional, and the infinite loop shown earlier is understood by Maple in exactly the same way as:

for internalVar from 1 by 1 to infinity while true do
statement-sequence
until false

When looping over the contents of a container, such as a one-dimensional array A, there are several possible approaches. The one closest to how it would be done in most other programming languages is (this example and those that follow can be copied and pasted into a Maple session):

A := Array([x,"foo",42]);
for i from lowerbound(A) to upperbound(A) do
print([i],A[i])
end do;

If only the entries in the container are of interest, it is not necessary to loop over the indices. Instead, one can write:

A := Array([x,"foo",42]);
for val in A do
print(val)
end do;

If both the indices and values are needed, one can write:

A := Array([x,"foo",42]);
for i, val in A do
print([i],val)
end do;

For a numerically indexed container such as an Array, this is equivalent to the for-from-to example. However, this method also works with arbitrarily indexed containers such as a Matrix or table:

M := LinearAlgebra:-RandomMatrix(2,3);
for i, val in M do
print([i],val)
end do;
for i, val in eval(T) do
print([i],val)
end do;

(The second example requires the call to eval due to last-name evaluation of tables in Maple, a topic for another post.)

As with a simple do-loop, a while and/or until clause can be added. For example, the following finds the first negative entry, if any, in a Matrix (traversing the Matrix in storage order):

M := LinearAlgebra:-RandomMatrix(2,3);
for i, val in M do
# nothing to do here
until val < 0;
if val < 0 then
print([i],val)
end if;

Notice that the test, val < 0, is written twice, since it is possible that the Matrix has no negative entry. Another way to write the same loop but only perform the test once is as follows:

M := LinearAlgebra:-RandomMatrix(2,3);
for i, val in M do
if val < 0 then
print([i],val);
break
end if;
end do;

Here, we perform the test within the loop, perform the desired processing on the found value (just printing in this case), and use a break statement to terminate the loop.

Sometimes, it is useful to abort the current iteration of the loop and move on to the next one. The next statement does exactly that. The following loop prints all the indices but only the positive values in a Matrix:

M := LinearAlgebra:-RandomMatrix(2,3);
for i, val in M do
print(INDEX=[i]);
if val < 0 then
next
end if;
print(VALUE=val);
end do;

(Note that a simple example like this would be better written by enclosing the printing of the value in an if-statement instead of using next. The latter is generally only used if the former is not possible.)

Maple's loop statements are very flexible and powerful, making it possible to write loops with complex combinations of termination conditions in a concise yet readable way. The ability to use while and/or until in conjunction with for means that break statements are often unnecessary, further improving clarity. ﻿