Loops and Control Structures

The execution of a Wolfram Language program involves the evaluation of a sequence of Wolfram Language expressions. In simple programs, the expressions to be evaluated may be separated by semicolons, and evaluated one after another. Often, however, you need to evaluate expressions several times, in some kind of "loop".

Simple looping constructs.

This evaluates (RefLink[Print, paclet:ref/Print])[i^2], with i running from 1 to 4:

Do[Print[i^2],{i,4}]

This executes an assignment for t in a loop with k running from 2 to 6 in steps of 2:

t=x;Do[t=1/(1+k t),{k,2,6,2}];t

The way iteration is specified in (RefLink[Do, paclet:ref/Do]) is exactly the same as in functions like (RefLink[Table, paclet:ref/Table]) and (RefLink[Sum, paclet:ref/Sum]). Just as in those functions, you can set up several nested loops by giving a sequence of iteration specifications to (RefLink[Do, paclet:ref/Do]).

This loops over values of i from 1 to 4, and for each value of i, loops over j from 1 to i-1:

Do[Print[{i,j}],{i,4},{j,i-1}]

Sometimes you may want to repeat a particular operation a certain number of times, without changing the value of an iteration variable. You can specify this kind of repetition in (RefLink[Do, paclet:ref/Do]) just as you can in (RefLink[Table, paclet:ref/Table]) and other iteration functions.

This repeats the assignment t=1/(1+t) three times:

t=x;Do[t=1/(1+t),{3}];t

You can put a procedure inside (RefLink[Do, paclet:ref/Do]):

t=67;Do[Print[t];t=Floor[t/2],{3}]

Applying functions repetitively.

(RefLink[Do, paclet:ref/Do]) allows you to repeat operations by evaluating a particular expression many times with different values for iteration variables. Often, however, you can make more elegant and efficient programs using the functional programming constructs discussed in "Applying Functions Repeatedly". (RefLink[Nest, paclet:ref/Nest])[f,x,n], for example, allows you to apply a function repeatedly to an expression.

This nests f three times:

Nest[f,x,3]

By nesting a pure function, you can get the same result as in the example with (RefLink[Do, paclet:ref/Do]) above:

Nest[Function[t,1/(1+t)],x,3]

(RefLink[Nest, paclet:ref/Nest]) allows you to apply a function a specified number of times. Sometimes, however, you may simply want to go on applying a function until the results you get no longer change. You can do this using (RefLink[FixedPoint, paclet:ref/FixedPoint])[f,x].

(RefLink[FixedPoint, paclet:ref/FixedPoint]) goes on applying a function until the result no longer changes:

FixedPoint[Function[t,Print[t];Floor[t/2]],67]

You can use (RefLink[FixedPoint, paclet:ref/FixedPoint]) to imitate the evaluation process in the Wolfram Language, or the operation of functions such as expr//.rules. (RefLink[FixedPoint, paclet:ref/FixedPoint]) goes on until two successive results it gets are the same. (RefLink[NestWhile, paclet:ref/NestWhile]) allows you to go on until an arbitrary function no longer yields (RefLink[True, paclet:ref/True]).

Nonlocal control of evaluation.

When the (RefLink[Throw, paclet:ref/Throw]) is encountered, evaluation stops, and the current value of i is returned as the value of the enclosing (RefLink[Catch, paclet:ref/Catch]):

Catch[Do[Print[i];If[i>3,Throw[i]],{i,10}]]

(RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]) provide a flexible way to control the process of evaluation in the Wolfram Language. The basic idea is that whenever a (RefLink[Throw, paclet:ref/Throw]) is encountered, the evaluation that is then being done is stopped, and the Wolfram Language immediately returns to the nearest appropriate enclosing (RefLink[Catch, paclet:ref/Catch]).

(RefLink[Scan, paclet:ref/Scan]) applies the function (RefLink[Print, paclet:ref/Print]) to each successive element in the list, and in the end just returns (RefLink[Null, paclet:ref/Null]):

Scan[Print,{7,6,5,4}]

The evaluation of (RefLink[Scan, paclet:ref/Scan]) stops as soon as (RefLink[Throw, paclet:ref/Throw]) is encountered, and the enclosing (RefLink[Catch, paclet:ref/Catch]) returns as its value the argument of (RefLink[Throw, paclet:ref/Throw]):

Catch[Scan[(Print[#];If[#<6,Throw[#]])&,{7,6,5,4}]]

The same result is obtained with (RefLink[Map, paclet:ref/Map]), even though (RefLink[Map, paclet:ref/Map]) would have returned a list if its evaluation had not been stopped by encountering a (RefLink[Throw, paclet:ref/Throw]):

Catch[Map[(Print[#];If[#<6,Throw[#]])&,{7,6,5,4}]]

You can use (RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]) to divert the operation of functional programming constructs, allowing for example the evaluation of such constructs to continue only until some condition has been met. Note that if you stop evaluation using (RefLink[Throw, paclet:ref/Throw]), then the structure of the result you get may be quite different from what you would have got if you had allowed the evaluation to complete.

Here is a list generated by repeated application of a function:

NestList[1/(#+1)&,-2.5,6]

Since there is no (RefLink[Throw, paclet:ref/Throw]) encountered, the result here is just as before:

Catch[NestList[1/(#+1)&,-2.5,6]]

Now the evaluation of the (RefLink[NestList, paclet:ref/NestList]) is diverted, and the single number given as the argument of (RefLink[Throw, paclet:ref/Throw]) is returned:

Catch[NestList[If[#>1,Throw[#],1/(#+1)]&,-2.5,6]]

(RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]) operate in a completely global way: it does not matter how or where a (RefLink[Throw, paclet:ref/Throw]) is generated—it will always stop evaluation and return to the enclosing (RefLink[Catch, paclet:ref/Catch]).

The (RefLink[Throw, paclet:ref/Throw]) stops the evaluation of f, and causes the (RefLink[Catch, paclet:ref/Catch]) to return just a, with no trace of f left:

Catch[f[Throw[a]]]

This defines a function which generates a (RefLink[Throw, paclet:ref/Throw]) when its argument is larger than 10:

g[x_]:=If[x>10,Throw[overflow],x!]

No (RefLink[Throw, paclet:ref/Throw]) is generated here:

Catch[g[4]]

But here the (RefLink[Throw, paclet:ref/Throw]) generated inside the evaluation of g returns to the enclosing (RefLink[Catch, paclet:ref/Catch]):

Catch[g[40]]

In small programs, it is often adequate to use (RefLink[Throw, paclet:ref/Throw])[value] and (RefLink[Catch, paclet:ref/Catch])[expr] in their simplest forms. But particularly if you write larger programs that contain many separate pieces, it is usually much better to use (RefLink[Throw, paclet:ref/Throw])[value,tag] and (RefLink[Catch, paclet:ref/Catch])[expr,form]. By keeping the expressions tag and form local to a particular piece of your program, you can then ensure that your (RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]) will also operate only within that piece.

Here the (RefLink[Throw, paclet:ref/Throw]) is caught by the inner (RefLink[Catch, paclet:ref/Catch]):

Catch[f[Catch[Throw[x,a],a]],b]

But here it is caught only by the outer (RefLink[Catch, paclet:ref/Catch]):

Catch[f[Catch[Throw[x,b],a]],b]

You can use patterns in specifying the tags which a particular (RefLink[Catch, paclet:ref/Catch]) should catch:

Catch[Throw[x,a],a|b]

This keeps the tag a completely local:

Module[{a},Catch[Throw[x,a],a]]

You should realize that there is no need for the tag that appears in (RefLink[Throw, paclet:ref/Throw]) to be a constant; in general it can be any expression.

Here the inner (RefLink[Catch, paclet:ref/Catch]) catches all throws with tags less than 4, and continues the (RefLink[Do, paclet:ref/Do]). But as soon as the tag reaches 4, the outer (RefLink[Catch, paclet:ref/Catch]) is needed:

Catch[Do[Catch[Throw[i^2,i],n_/;n<4],{i,10}],_]

When you use (RefLink[Catch, paclet:ref/Catch])[expr,form] with (RefLink[Throw, paclet:ref/Throw])[value,tag], the value returned by (RefLink[Catch, paclet:ref/Catch]) is simply the expression value given in the (RefLink[Throw, paclet:ref/Throw]). If you use (RefLink[Catch, paclet:ref/Catch])[expr,form,f], however, then the value returned by (RefLink[Catch, paclet:ref/Catch]) is instead f[value,tag].

Here f is applied to the value and tag in the (RefLink[Throw, paclet:ref/Throw]):

Catch[Throw[x,a],a,f]

If there is no (RefLink[Throw, paclet:ref/Throw]), f is never used:

Catch[x,a,f]

General loop constructs.

Functions like (RefLink[Do, paclet:ref/Do]), (RefLink[Nest, paclet:ref/Nest]), and (RefLink[FixedPoint, paclet:ref/FixedPoint]) provide structured ways to make loops in Wolfram Language programs, while (RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]) provide opportunities for modifying this structure. Sometimes, however, you may want to create loops that even from the outset have less structure. And in such cases, you may find it convenient to use the functions (RefLink[While, paclet:ref/While]) and (RefLink[For, paclet:ref/For]), which perform operations repeatedly, stopping when a specified condition fails to be true.

The (RefLink[While, paclet:ref/While]) loop continues until the condition fails:

n=17;While[(n=Floor[n/2])!=0,Print[n]]

The functions (RefLink[While, paclet:ref/While]) and (RefLink[For, paclet:ref/For]) in the Wolfram Language are similar to the control structures while and for in languages such as C. Notice, however, that there are a number of important differences. For example, the roles of comma and semicolon are reversed in Wolfram Language (RefLink[For, paclet:ref/For]) loops relative to C language ones.

This is a very common form for a (RefLink[For, paclet:ref/For]) loop. i++ increments the value of i:

For[i=1,i<4,i++,Print[i]]

Here is a more complicated (RefLink[For, paclet:ref/For]) loop. Notice that the loop terminates as soon as the test i^2<10 fails:

For[i=1;t=x,i^2<10,i++,t=t^2+i;Print[t]]

In the Wolfram Language, both (RefLink[While, paclet:ref/While]) and (RefLink[For, paclet:ref/For]) always evaluate the loop test before evaluating the body of the loop. As soon as the loop test fails to be (RefLink[True, paclet:ref/True]), (RefLink[While, paclet:ref/While]) and (RefLink[For, paclet:ref/For]) terminate. The body of the loop is thus only evaluated in situations where the loop test is (RefLink[True, paclet:ref/True]).

The loop test fails immediately, so the body of the loop is never evaluated:

While[False,Print[x]]

In a (RefLink[While, paclet:ref/While]) or (RefLink[For, paclet:ref/For]) loop, or in general in any Wolfram Language procedure, the Wolfram Language expressions you give are evaluated in a definite sequence. You can think of this sequence as defining the "flow of control" in the execution of a Wolfram Language program.

In most cases, you should try to keep the flow of control in your Wolfram Language programs as simple as possible. The more the flow of control depends for example on specific values generated during the execution of the program, the more difficult you will typically find it to understand the structure and operation of the program.

Functional programming constructs typically involve very simple flow of control. (RefLink[While, paclet:ref/While]) and (RefLink[For, paclet:ref/For]) loops are always more complicated, since they are set up to make the flow of control depend on the values of the expressions given as tests. Nevertheless, even in such loops, the flow of control does not usually depend on the values of expressions given in the body of the loop.

In some cases, however, you may need to construct Wolfram Language programs in which the flow of control is affected by values generated during the execution of a procedure or of the body of a loop. One way to do this, which fits in with functional programming ideas, is to use (RefLink[Throw, paclet:ref/Throw]) and (RefLink[Catch, paclet:ref/Catch]). But the Wolfram Language also provides various functions for modifying the flow of control which work like in languages such as C.

Control flow functions.

The (RefLink[Break, paclet:ref/Break])[] causes the loop to terminate as soon as t exceeds 19:

t=1;Do[t*=k;Print[t];If[t>19,Break[]],{k,10}]

When k<3, the (RefLink[Continue, paclet:ref/Continue])[] causes the loop to be continued, without executing t+=2:

t=1;Do[t*=k;Print[t];If[k<3,Continue[]];t+=2,{k,10}]

(RefLink[Return, paclet:ref/Return])[expr] allows you to exit a particular function, returning a value. You can think of (RefLink[Throw, paclet:ref/Throw]) as a kind of nonlocal return which allows you to exit a whole sequence of nested functions. Such behavior can be convenient for handling certain error conditions.

Here is an example of the use of (RefLink[Return, paclet:ref/Return]). This particular procedure could equally well have been written without using (RefLink[Return, paclet:ref/Return]):

f[x_]:=(If[x>5,Return[big]];t=x^3;Return[t-7])

When the argument is greater than 5, the first (RefLink[Return, paclet:ref/Return]) in the procedure is used:

f[10]

This function "throws" error if its argument is negative:

h[x_]:=If[x<0,Throw[error],Sqrt[x]]

No (RefLink[Throw, paclet:ref/Throw]) is generated here:

Catch[h[6]+2]

But in this case a (RefLink[Throw, paclet:ref/Throw]) is generated, and the whole (RefLink[Catch, paclet:ref/Catch]) returns the value error:

Catch[h[-6]+2]

Functions like (RefLink[Continue, paclet:ref/Continue])[] and (RefLink[Break, paclet:ref/Break])[] allow you to "transfer control" to the beginning or end of a loop in a Wolfram Language program. Sometimes you may instead need to transfer control to a particular element in a Wolfram Language procedure. If you give a (RefLink[Label, paclet:ref/Label]) as an element in a procedure, you can use (RefLink[Goto, paclet:ref/Goto]) to transfer control to this element.

This goes on looping until q exceeds 6:

(q=2;Label[begin];Print[q];q+=3;If[q<6,Goto[begin]])

Note that you can use (RefLink[Goto, paclet:ref/Goto]) in a particular Wolfram Language procedure only when the (RefLink[Label, paclet:ref/Label]) it specifies occurs as an element of the same Wolfram Language procedure. In general, use of (RefLink[Goto, paclet:ref/Goto]) reduces the degree of structure that can readily be perceived in a program, and therefore makes the operation of the program more difficult to understand.