REDUCE

5.7 Compound Statements

Often the desired process can best (or only) be described as a series of steps to be carried out one after the other. In many cases, this can be achieved by use of the group statement. However, each step often provides some intermediate result, until at the end we have the final result wanted. Alternatively, iterations on the steps are needed that are not possible with constructs such as WHILE or REPEAT statements. In such cases the steps of the process must be enclosed between the words BEGIN and END forming what is technically called a block or compound statement. Such a compound statement can in fact be used wherever a group statement appears. The converse is not true: BEGIN …END can be used in ways that <<>> cannot.

If intermediate results must be formed, local variables must be provided in which to store them. Local means that their values are deleted as soon as the block’s operations are complete, and there is no conflict with variables outside the block that happen to have the same name. Local variables are created by a SCALAR declaration immediately after the BEGIN:

     scalar a,b,c,z;

If more convenient, several SCALAR declarations can be given one after another:

     scalar a,b,c;  
     scalar z;

In place of SCALAR one can also use the declarations INTEGER or REAL. In the present version of REDUCE variables declared INTEGER are expected to have only integer values, and are initialized to 0. REAL variables on the other hand are currently treated as algebraic mode SCALARs.

CAUTION: INTEGER, REAL and SCALAR declarations can only be given immediately after a BEGIN. An error will result if they are used after other statements in a block (including ARRAY and OPERATOR declarations, which are global in scope), or outside the top-most block (e.g., at the top level). All variables declared SCALAR are automatically initialized to zero in algebraic mode (NIL in symbolic mode).

Any symbols not declared as local variables in a block refer to the variables of the same name in the current calling environment. In particular, if they are not so declared at a higher level (e.g., in a surrounding block or as parameters in a calling procedure), their values can be permanently changed.

Following the SCALAR declaration(s), if any, write the statements to be executed, one after the other, separated by delimiters (e.g., ; or $) (it doesn’t matter which). However, from a stylistic point of view, ; is preferred.

The last statement in the body, just before END, need not have a terminator (since the BEGINEND are in a sense brackets confining the block statements). The last statement must also be the command RETURN followed by the variable or expression whose value is to be the value returned by the procedure. If the RETURN is omitted (or nothing is written after the word RETURN) the procedure will have no value or the value zero, depending on how it is used (and NIL in symbolic mode). Remember to put a terminator after the END.

Example:

Given a previously assigned integer value for N, the following block will compute the Legendre polynomial of degree N in the variable X:

        begin scalar seed,deriv,top,fact;  
           seed:=1/(y^2 - 2*x*y +1)^(1/2);  
           deriv:=df(seed,y,n);  
           top:=sub(y=0,deriv);  
           fact:=for i:=1:n product i;  
           return top/fact  
        end;

5.7.1 Compound Statements with GO TO

It is possible to have more complicated structures inside the BEGINEND brackets than indicated in the previous example. That the individual lines of the program need not be assignment statements, but could be almost any other kind of statement or command, needs no explanation. For example, conditional statements, and WHILE and REPEAT constructions, have an obvious role in defining more intricate blocks.

If these structured constructs don’t suffice, it is possible to use labels and GO TOs within a compound statement, and also to use RETURN in places within the block other than just before the END. The following subsections discuss these matters in detail. For many readers the following example, presenting one possible definition of a process to calculate the factorial of N for preassigned N will suffice:

Example:

        begin scalar m;  
            m:=1;  
         l: if n=0 then return m;  
            m:=m*n;  
            n:=n-1;  
            go to l  
        end;

5.7.2 Labels and GO TO Statements

Within a BEGIN …END compound statement it is possible to label statements, and transfer to them out of sequence using GOTO statements. Only statements on the top level inside compound statements can be labeled, not ones inside subsidiary constructions like << >>, IFTHEN…, WHILEDO…, etc.

Labels and GO TO statements have the syntax:

go to statement
::=
GO TO labelGOTO label
label
::=
identifier
labeled statement
::=
label:statement

Note that statement names cannot be used as labels.

While GO TO is an unconditional transfer, it is frequently used in conditional statements such as

        if x>5 then go to abcd;

giving the effect of a conditional transfer.

Transfers using GO TOs can only occur within the block in which the GO TO is used. In other words, you cannot transfer from an inner block to an outer block using a GO TO. However, if a group statement occurs within a compound statement, it is possible to jump out of that group statement to a point within the compound statement using a GO TO.

5.7.3 RETURN Statements

The value corresponding to a BEGINEND compound statement, such as a procedure body, is normally 0 (NIL in symbolic mode). By executing a RETURN statement in the compound statement a different value can be returned. After a RETURN statement is executed, no further statements within the compound statement are executed.

Examples:

        return x+y;  
        return m;  
        return;

Note that parentheses are not required around the x+y, although they are permitted. The last example is equivalent to return 0 or return nil, depending on whether the block is used as part of an expression or not.

Since RETURN actually moves up only one block level, in a sense the casual user is not expected to understand, we tabulate some cautions concerning its use.

  1. RETURN can be used on the top level inside the compound statement, i.e. as one of the statements bracketed together by the BEGINEND
  2. RETURN can be used within a top level << >> construction within the compound statement. In this case, the RETURN transfers control out of both the group statement and the compound statement.
  3. RETURN can be used within an IFTHENELSE… on the top level within the compound statement.

NOTE: At present, there is no construct provided to permit early termination of a FOR, WHILE, or REPEAT statement. In particular, the use of RETURN in such cases results in a syntax error. For example,

        begin scalar y;  
           y := for i:=0:99 do if a(i)=x then return b(i);  
           ...

will lead to an error.