Wolfram Research, Inc.

2.5.4 The Standard Evaluation Procedure

This section describes the standard procedure used by Mathematica to evaluate expressions. This procedure is the one followed for most kinds of expressions. There are however some kinds of expressions, such as those used to represent Mathematica programs and control structures, which are evaluated in a non-standard way. The treatment of such expressions is discussed in the sections that follow this one.

In the standard evaluation procedure, Mathematica first evaluates the head of an expression, and then evaluates each element of the expressions. These elements are in general themselves expressions, to which the same evaluation procedure is recursively applied.

The three Print functions are evaluated in turn, each printing its argument, then returning the value Null.

In[1]:= {Print[1], Print[2], Print[3]}

Out[1]=

This assigns the symbol ps to be Plus.

In[2]:= ps = Plus

Out[2]=

The head ps is evaluated first, so this expression behaves just like a sum of terms.

In[3]:= ps[ps[a, b], c]

Out[3]=

As soon as Mathematica has evaluated the head of an expression, it sees whether the head is a symbol that has attributes. If the symbol has the attributes Orderless, Flat or Listable, then immediately after evaluating the elements of the expression Mathematica performs the transformations associated with these attributes.

The next step in the standard evaluation procedure is to use definitions that Mathematica knows for the expression it is evaluating. Mathematica first tries to use definitions that you have made, and if there are none that apply, it tries built-in definitions.

If Mathematica finds a definition that applies, it performs the corresponding transformation on the expression. The result is another expression, which must then in turn be evaluated according to the standard evaluation procedure.

The standard evaluation procedure.

As discussed in Section 2.5.1, Mathematica follows the principle that each expression is evaluated until no further definitions apply. This means that Mathematica must continue re-evaluating results until it gets an expression which remains unchanged through the evaluation procedure.

Here is an example that shows how the standard evaluation procedure works on a simple expression. We assume that a = 7.

A simple example of evaluation in Mathematica.

Mathematica provides various ways to "trace" the evaluation process, as discussed in Section 2.5.10. The function Trace[expr] gives a nested list showing each subexpression generated during evaluation. (Note that the standard evaluation traverses the expression tree in a depth-first way, so that the smallest subparts of the expression appear first in the results of Trace.)

First set a to 7.

In[4]:= a = 7

Out[4]=

This gives a nested list of all the subexpressions generated during the evaluation of the expression.

In[5]:= Trace[2 a x + a^2 + 1]

Out[5]=

The order in which Mathematica applies different kinds of definitions is important. The fact that Mathematica applies definitions you have given before it applies built-in definitions means that you can give definitions which override the built-in ones, as discussed in Section 2.4.12.

This expression is evaluated using the built-in definition for ArcSin.

In[6]:= ArcSin[1]

Out[6]=

You can give your own definitions for ArcSin. You need to remove the protection attribute first.

In[7]:= Unprotect[ArcSin]; ArcSin[1] = 5Pi/2;

Your definition is used before the one that is built in.

In[8]:= ArcSin[1]

Out[8]=

As discussed in Section 2.4.10, you can associate definitions with symbols either as upvalues or downvalues. Mathematica always tries upvalue definitions before downvalue ones.

If you have an expression like f[g[x]], there are in general two sets of definitions that could apply: downvalues associated with f, and upvalues associated with g. Mathematica tries the definitions associated with g before those associated with f.

This ordering follows the general strategy of trying specific definitions before more general ones. By applying upvalues associated with arguments before applying downvalues associated with a function, Mathematica allows you to make definitions for special arguments which override the general definitions for the function with any arguments.

This defines a rule for f[g[x_]], to be associated with f.

In[9]:= f/: f[g[x_]] := frule[x]

This defines a rule for f[g[x_]], to be associated with g.

In[10]:= g/: f[g[x_]] := grule[x]

The rule associated with g is tried before the rule associated with f.

In[11]:= f[g[2]]

Out[11]=

If you remove rules associated with g, the rule associated with f is used.

In[12]:= Clear[g] ; f[g[1]]

Out[12]=

The order in which definitions are applied.

Most functions such as Plus that are built into Mathematica have downvalues. There are, however, some objects in Mathematica which have built-in upvalues. For example, SeriesData objects, which represent power series, have built-in upvalues with respect to various mathematical operations.

For an expression like f[g[x]], the complete sequence of definitions that are tried in the standard evaluation procedure is:

Definitions you have given associated with g;

Built-in definitions associated with g;

Definitions you have given associated with f;

Built-in definitions associated with f.

The fact that upvalues are used before downvalues is important in many situations. In a typical case, you might want to define an operation such as composition. If you give upvalues for various objects with respect to composition, these upvalues will be used whenever such objects appear. However, you can also give a general procedure for composition, to be used if no special objects are present. You can give this procedure as a downvalue for composition. Since downvalues are tried after upvalues, the general procedure will be used only if no objects with upvalues are present.

Here is a definition associated with q for composition of "q objects".

In[13]:= q/: comp[q[x_], q[y_]] := qcomp[x, y]

Here is a general rule for composition, associated with comp.

In[14]:= comp[f_[x_], f_[y_]] := gencomp[f, x, y]

If you compose two q objects, the rule associated with q is used.

In[15]:= comp[q[1], q[2]]

Out[15]=

If you compose r objects, the general rule associated with comp is used.

In[16]:= comp[r[1], r[2]]

Out[16]=

In general, there can be several objects that have upvalues in a particular expression. Mathematica first looks at the head of the expression, and tries any upvalues associated with it. Then it successively looks at each element of the expression, trying any upvalues that exist. Mathematica performs this procedure first for upvalues that you have explicitly defined, and then for upvalues that are built in. The procedure means that in a sequence of elements, upvalues associated with earlier elements take precedence over those associated with later elements.

This defines an upvalue for p with respect to c.

In[17]:= p/: c[l___, p[x_], r___] := cp[x, {l, r}]

This defines an upvalue for q.

In[18]:= q/: c[l___, q[x_], r___] := cq[x, {l, r}]

Which upvalue is used depends on which occurs first in the sequence of arguments to c.

In[19]:= {c[p[1], q[2]], c[q[1], p[2]]}

Out[19]=