====================================================================
for loops
====================================================================

FriCAS provide the for and in keywords in repeat loops, allowing you
to integrate across all elements of a list, or to have a variable take
on integral values from a lower bound to an upper bound. We shall refer
to these modifying clauses of repeat loops as for clauses. These clauses
can be present in addition to while clauses (See )help while). As with
all other types of repeat loops, leave (see )help leave) can be used to 
prematurely terminate evaluation of the loop.

The syntax for a simple loop using for is

  for iterator repeat loopbody

The iterator has several forms. Each form has an end test which is
evaluted before loopbody is evaluated. A for loop terminates immediately
when the end test succeeds (evaluates to true) or when a leave or return
expression is evaluated in loopbody. The value returned by the loop is 
the unique value of Void.

====================================================================
for i in n..m repeat
====================================================================

If for is followed by a variable name, the in keyword and then an integer
segment of the form n..m, the end test for this loop is the predicate 
i > m. The body of the loop is evaluated m-n+1 times if this number is
greater than 0. If this number is less than or equal to 0, the loop body
is not evaluated at all.

The variable i has the value n, n+1, ..., m for successive iterations
of the loop body. The loop variable is a local variable within the loop
body. Its value is not available outside the loop body and its value and
type within the loop body completely mask any outer definition of a
variable with the same name.

  for i in 10..12 repeat output(i**3)
   1000
   1331
   1728
                      Type: Void

The loop prints the values of 10^3, 11^3, and 12^3.

  a := [1,2,3]
   [1,2,3]
                      Type: List PositiveInteger

  for i in 1..#a repeat output(a.i)
   1
   2
   3
                      Type: Void

Iterate across this list using "." to access the elements of a list
and the # operation to count its elements.

This type of iteration is applicable to anything that uses ".". You 
can also use it with functions that use indices to extract elements.

   m := matrix [[1,2],[4,3],[9,0]]
    +-    -+
    | 1  2 |
    | 4  3 |
    | 9  0 |
    +-    -+
                      Type: Matrix Integer

Define m to be a matrix.

   for i in 1..nrows(m) repeat output row(m.i)
    [1,2]
    [4,3]
    [9,0]
                      Type: Void

Display the rows of m.

You can iterate with for-loops.

   for i in 1..5 repeat
     if odd?(i) then iterate
     output(i)
    2
    4
                      Type: Void

Display the even integers in a segment.

====================================================================
for i in n..m by s repeat
====================================================================

By default, the difference between values taken on by a variable in
loops such as 

  for i in n..m repeat ...

is 1. It is possible to supply another, possibly negative, step value
by using the by keyword along with for and in. Like the upper and lower
bounds, the step value following the by keyword must be an integer. Note
that the loop

  for i in 1..2 by 0 repeat output(i)

will not terminate by itself, as the step value does not change the
index from its initial value of 1.

  for i in 1..5 by 2 repeat output(i)
   1
   3
   5
                      Type: Void

This expression displays the odd integers between two bounds.

  for i in 5..1 by -2 repeat output(i)
   5
   3
   1
                      Type: Void

Use this to display the numbers in reverse order.

====================================================================
for i in n.. repeat
====================================================================

If the value after the ".." is omitted, the loop has no end test. A
potentially infinite loop is thus created. The variable is given the
successive values n, n+1, n+2, ... and the loop is terminated only
if a leave or return expression is evaluated in the loop body. However,
you may also add some other modifying clause on the repeat, for example,
a while clause, to stop the loop.

  for i in 15.. while not prime?(i) repeat output(i)
   15
   16
                      Type: Void

This loop displays the integers greater than or equal to 15 and less
than the first prime number greater than 15.

====================================================================
for x in l repeat
====================================================================

Another variant of the for loop has the form:

  for x in list repeat loopbody

This form is used when you want to iterate directly over the elements
of a list. In this form of the for loop, the variable x takes on the
value of each successive element in l. The end test is most simply
stated in English: "are there no more x in l?"

  l := [0, -5, 3]
   [0, -5, 3]
                      Type: List Integer

  for x in l repeat output(x)
   0
   -5
   3
                      Type: Void

This displays all of the elements of the list l, one per line.

Since the list constructing expression 

  expand [n..m]

creates the list

  [n, n+1, ..., m]

you might be tempted to think that the loops

  for i in n..m repeat output(i)

and

  for x in expand [n..m] repeat output(x)

are equivalent. The second form first creates the expanded list
(no matter how large it might be) and then does the iteration. The
first form potentially runs in much less space, as the index variable
i is simply incremented once per loop and the list is not actually
created. Using the first form is much more efficient.

Of course, sometimes you really want to iterate across a specific list.
This displays each of the factors of 2400000:

  for f in factors(factor(2400000)) repeat output(f)
   [factor= 2, exponent= 8]
   [factor= 3, exponent= 1]
   [factor= 5, exponent= 5]
                      Type: Void

