Evaluation of Expressions

Principles of Evaluation
The fundamental operation that the Wolfram Language performs is evaluation. Whenever you enter an expression, the Wolfram Language evaluates the expression, then returns the result.
Evaluation in the Wolfram Language works by applying a sequence of definitions. The definitions can either be ones you explicitly entered, or ones that are built into the Wolfram Language.
Thus, for example, the Wolfram Language evaluates the expression 6+7 using a builtin procedure for adding integers. Similarly, the Wolfram Language evaluates the algebraic expression x-3x+1 using a builtin simplification procedure. If you had made the definition x=5, then the Wolfram Language would use this definition to reduce x-3x+1 to -9.
The two most central concepts in the Wolfram Language are probably expressions and evaluation. "Expressions" discusses how all the different kinds of objects that the Wolfram Language handles are represented in a uniform way using expressions. This tutorial describes how all the operations that the Wolfram Language can perform can also be viewed in a uniform way as examples of evaluation.
Computation
5+611
Simplification
x-3x+11-2x
Execution
x=55
Some interpretations of evaluation.
The Wolfram Language is an infinite evaluation system. When you enter an expression, the Wolfram Language will keep on using definitions it knows until it gets a result to which no definitions apply.
This defines x1 in terms of x2, and then defines x2:
If you ask for x1, the Wolfram Language uses all the definitions it knows to give you a result:
Here is a recursive definition in which the factorial function is defined in terms of itself:
If you ask for fac[10], the Wolfram Language will keep on applying the definitions you have given until the result it gets no longer changes:
When the Wolfram Language has used all the definitions it knows, it gives whatever expression it has obtained as the result. Sometimes the result may be an object such as a number. But usually the result is an expression in which some objects are represented in a symbolic form.
The Wolfram Language uses its builtin definitions for simplifying sums, but knows no definitions for f[3], so leaves this in symbolic form:
The Wolfram Language follows the principle of applying definitions until the result it gets no longer changes. This means that if you take the final result that the Wolfram Language gives, and enter it as Wolfram Language input, you will get back the same result again. (There are some subtle cases discussed in "Controlling Infinite Evaluation" in which this does not occur.)
If you type in a result from the Wolfram Language, you get back the same expression again:
At any given time, the Wolfram Language can only use those definitions that it knows at that time. If you add more definitions later, however, the Wolfram Language will be able to use these. The results you get from the Wolfram Language may change in this case.
Here is a new definition for the function f:
With the new definition, the results you get can change:
The simplest examples of evaluation involve using definitions such as f[x_]=x^2 which transform one expression directly into another. But evaluation is also the process used to execute programs written in the Wolfram Language. Thus, for example, if you have a procedure consisting of a sequence of Wolfram Language expressions, some perhaps representing conditionals and loops, the execution of this procedure corresponds to the evaluation of these expressions. Sometimes the evaluation process may involve evaluating a particular expression several times, as in a loop.
The expression Print[zzzz] is evaluated three times during the evaluation of the Do expression:
Reducing Expressions to Their Standard Form
The builtin functions in the Wolfram Language operate in a wide variety of ways. But many of the mathematical functions share an important approach: they are set up so as to reduce classes of mathematical expressions to standard forms.
The builtin definitions for the Plus function, for example, are set up to write any sum of terms in a standard unparenthesized form. The associativity of addition means that expressions like (a+b)+c, a+(b+c) and a+b+c are all equivalent. But for many purposes it is convenient for all these forms to be reduced to the single standard form a+b+c. The builtin definitions for Plus are set up to do this.
Through the builtin definitions for Plus, this expression is reduced to a standard unparenthesized form:
Whenever the Wolfram Language knows that a function is associative, it tries to remove parentheses (or nested invocations of the function) to get the function into a standard "flattened" form.
A function like addition is not only associative, but also commutative, which means that expressions like a+c+b and a+b+c with terms in different orders are equal. Once again, the Wolfram Language tries to put all such expressions into a "standard" form. The standard form it chooses is the one in which all the terms are in a definite order, corresponding roughly to alphabetical order.
The Wolfram Language sorts the terms in this sum into a standard order:
flat (associative)
is equivalent to , etc.
orderless (commutative)
is equivalent to , etc.
Two important properties that the Wolfram Language uses in reducing certain functions to standard form.
There are several reasons to try to put expressions into standard forms. The most important is that if two expressions are really in standard form, it is obvious whether or not they are equal.
When the two sums are put into standard order, they are immediately seen to be equal, so that two f's cancel, leaving the result 0:
You could imagine finding out whether a+c+b was equal to c+a+b by testing all possible orderings of each sum. It is clear that simply reducing both sums to standard form is a much more efficient procedure.
One might think that the Wolfram Language should somehow automatically reduce all mathematical expressions to a single standard canonical form. With all but the simplest kinds of expressions, however, it is quite easy to see that you do not want the same standard form for all purposes.
For polynomials, for example, there are two obvious standard forms, which are good for different purposes. The first standard form for a polynomial is a simple sum of terms, as would be generated in the Wolfram Language by applying the function Expand. This standard form is most appropriate if you need to add and subtract polynomials.
There is, however, another possible standard form that you can use for polynomials. By applying Factor, you can write any polynomial as a product of irreducible factors. This canonical form is useful if you want to do operations like division.
Expanded and factored forms are in a sense both equally good standard forms for polynomials. Which one you decide to use simply depends on what you want to use it for. As a result, the Wolfram Language does not automatically put polynomials into one of these two forms. Instead, it gives you functions like Expand and Factor that allow you explicitly to put polynomials in whatever form you want.
Here is a list of two polynomials that are mathematically equal:
You can write both of them in expanded form just by applying Expand. In this form, the equality of the polynomials is obvious:
You can also see that the polynomials are equal by writing them both in factored form:
Although it is clear that you do not always want expressions reduced to the same standard form, you may wonder whether it is at least possible to reduce all expressions to some standard form.
There is a basic result in the mathematical theory of computation which shows that this is, in fact, not always possible. You cannot guarantee that any finite sequence of transformations will take any two arbitrarily chosen expressions to a standard form.
In a sense, this is not particularly surprising. If you could in fact reduce all mathematical expressions to a standard form, then it would be quite easy to tell whether any two expressions were equal. The fact that so many of the difficult problems of mathematics can be stated as questions about the equality of expressions suggests that this can in fact be difficult.
Attributes
Definitions such as f[x_]=x^2 specify values for functions. Sometimes, however, you need to specify general properties of functions, without necessarily giving explicit values.
The Wolfram Language provides a selection of attributes that you can use to specify various properties of functions. For example, you can use the attribute Flat to specify that a particular function is "flat", so that nested invocations are automatically flattened, and it behaves as if it were associative.
This assigns the attribute Flat to the function f:
Now f behaves as a flat, or associative, function, so that nested invocations are automatically flattened:
Attributes like Flat can affect not only evaluation, but also operations such as pattern matching. If you give definitions or transformation rules for a function, you must be sure to have specified the attributes of the function first.
Here is a definition for the flat function f:
Because f is flat, the definition is automatically applied to every subsequence of arguments:
Attributes[f]
give the attributes of f
Attributes[f]={attr1,attr2,}
set the attributes of f
Attributes[f]={}
set f to have no attributes
SetAttributes[f,attr]
add attr to the attributes of f
ClearAttributes[f,attr]
remove attr from the attributes of f
Manipulating attributes of symbols.
This shows the attributes assigned to f:
This removes the attributes assigned to f:
Orderless
orderless, commutative function (arguments are sorted into standard order)
Flat
flat, associative function (arguments are "flattened out")
OneIdentity
f[f[a]], etc. are equivalent to a for pattern matching
Listable
f is automatically "threaded" over lists that appear as arguments (e.g., f[{a,b}] becomes {f[a],f[b]})
Constant
all derivatives of f are zero
NumericFunction
f is assumed to have a numerical value when its arguments are numeric quantities
Protected
values of f cannot be changed
Locked
attributes of f cannot be changed
ReadProtected
values of f cannot be read
HoldFirst
the first argument of f is not evaluated
HoldRest
all but the first argument of f are not evaluated
HoldAll
none of the arguments of f are evaluated
HoldAllComplete
the arguments of f are treated as completely inert
NHoldFirst
the first argument of f is not affected by N
NHoldRest
all but the first argument of f are not affected by N
NHoldAll
none of the arguments of f are affected by N
SequenceHold
Sequence objects appearing in the arguments of f are not flattened out
Temporary
f is a local variable, removed when no longer used
Stub
Needs is automatically called if f is ever explicitly input
The complete list of attributes for symbols in the Wolfram Language.
Here are the attributes for the builtin function Plus:
An important attribute assigned to builtin mathematical functions in the Wolfram Language is the attribute Listable. This attribute specifies that a function should automatically be distributed or "threaded" over lists that appear as its arguments. This means that the function effectively gets applied separately to each element in any lists that appear as its arguments.
The builtin Log function is Listable:
This defines the function p to be listable:
Now p is automatically threaded over lists that appear as its arguments:
Many of the attributes you can assign to functions in the Wolfram Language directly affect the evaluation of those functions. Some attributes, however, affect only other aspects of the treatment of functions. For example, the attribute OneIdentity affects only pattern matching, as discussed in "Flat and Orderless Functions". Similarly, the attribute Constant is only relevant in differentiation, and operations that rely on differentiation.
The Protected attribute affects assignments. The Wolfram Language does not allow you to make any definition associated with a symbol that carries this attribute. The functions Protect and Unprotect discussed in "Modifying Built-in Functions" can be used as alternatives to SetAttributes and ClearAttributes to set and clear this attribute. As discussed in "Modifying Built-in Functions", most builtin Wolfram Language objects are initially protected so that you do not make definitions for them by mistake.
Here is a definition for the function g:
This sets the Protected attribute for g:
Now you cannot modify the definition of g:
You can usually see the definitions you have made for a particular symbol by typing ?f, or by using a variety of builtin Wolfram Language functions. However, if you set the attribute ReadProtected, the Wolfram Language will not allow you to look at the definition of a particular symbol. It will nevertheless continue to use the definitions in performing evaluation.
Although you cannot modify it, you can still look at the definition of g:
This sets the ReadProtected attribute for g:
Now you can no longer read the definition of g:
Functions like SetAttributes and ClearAttributes usually allow you to modify the attributes of a symbol in any way. However, if you once set the Locked attribute on a symbol, then the Wolfram Language will not allow you to modify the attributes of that symbol for the remainder of your Wolfram System session. Using the Locked attribute in addition to Protected or ReadProtected, you can arrange for it to be impossible for users to modify or read definitions.
Clear[f]
remove values for f, but not attributes
ClearAll[f]
remove both values and attributes of f
Clearing values and attributes.
This clears values and attributes of p which was given attribute Listable above:
Now p is no longer listable:
By defining attributes for a function you specify properties that the Wolfram Language should assume whenever that function appears. Often, however, you want to assume the properties only in a particular instance. In such cases, you will be better off not to use attributes, but instead to call a particular function to implement the transformation associated with the attributes.
By explicitly calling Thread, you can implement the transformation that would be done automatically if p were listable:
OrderlessSort[f[args]]
FlatFlatten[f[args]]
ListableThread[f[args]]
ConstantDt[expr,Constants->f]
Functions that perform transformations associated with some attributes.
Attributes in the Wolfram Language can only be permanently defined for single symbols. However, the Wolfram Language also allows you to set up pure functions which behave as if they carry attributes.
Function[vars,body,{attr1,}]
a pure function with attributes attr1,
Pure functions with attributes.
This pure function applies p to the whole list:
By adding the attribute Listable, the function gets distributed over the elements of the list before applying p:
The Standard Evaluation Procedure
Here the standard procedure used by the Wolfram System to evaluate expressions is described. This procedure is the one followed for most kinds of expression. There are, however, some kinds of expressions, such as those used to represent the Wolfram System programs and control structures, that are evaluated in a nonstandard way.
In the standard evaluation procedure, the Wolfram System first evaluates the head of an expression and then evaluates each element of the expression. 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:
This assigns the symbol ps to be Plus:
The head ps is evaluated first, so this expression behaves just like a sum of terms:
As soon as the Wolfram System 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 the Wolfram System performs the transformations associated with these attributes.
The next step in the standard evaluation procedure is to use definitions that the Wolfram System knows for the expression it is evaluating. The Wolfram System first tries to use definitions that you have made, and if there are none that apply, it tries builtin definitions.
If the Wolfram System 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.
Evaluate the head of the expression.
Evaluate each element in turn.
Apply transformations associated with the attributes Orderless, Listable, and Flat.
Apply any definitions that you have given.
Apply any builtin definitions.
Evaluate the result.
The standard evaluation procedure.
As discussed in "Principles of Evaluation", the Wolfram System follows the principle that each expression is evaluated until no further definitions apply. This means that the Wolfram System must continue reevaluating results until it gets an expression that remains unchanged through the evaluation procedure.
Here is an example that shows how the standard evaluation procedure works on a simple expression. Assume that a=7.
2ax+a^2+1
here is the original expression
Plus[Times[2,a,x],Power[a,2],1]
this is the internal form
Times[2,a,x]
this is evaluated first
Times[2,7,x]
a is evaluated to give 7
Times[14,x]
builtin definitions for Times give this result
Power[a,2]
this is evaluated next
Power[7,2]
here is the result after evaluating a
49
builtin definitions for Power give this result
Plus[Times[14,x],49,1]
here is the result after the arguments of Plus have been evaluated
Plus[50,Times[14,x]]
builtin definitions for Plus give this result
50+14x
the result is printed like this
A simple example of evaluation in the Wolfram System.
The Wolfram System provides various ways to "trace" the evaluation process, as discussed in "Tracing Evaluation". 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 depthfirst way, so that the smallest subparts of the expression appear first in the results of Trace.)
First set a to 7:
This gives a nested list of all the subexpressions generated during the evaluation of the expression:
The order in which the Wolfram System applies different kinds of definitions is important. The fact that the Wolfram System applies definitions you have given before it applies builtin definitions means that you can give definitions that override the builtin ones, as discussed in "Modifying Built-in Functions".
This expression is evaluated using the builtin definition for ArcSin:
You can give your own definitions for ArcSin. You need to remove the protection attribute first:
Your definition is used before the one that is built in:
As discussed in "Associating Definitions with Different Symbols", you can associate definitions with symbols either as upvalues or downvalues. The Wolfram System 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. The Wolfram System 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, the Wolfram System allows you to make definitions for special arguments that override the general definitions for the function with any arguments.
This defines a rule for f[g[x_]], to be associated with f:
This defines a rule for f[g[x_]], to be associated with g:
The rule associated with g is tried before the rule associated with f:
If you remove rules associated with g, the rule associated with f is used:
Definitions associated with g are applied before definitions associated with f in the expression f[g[x]].
The order in which definitions are applied.
Most functions such as Plus that are built into the Wolfram System have downvalues. There are, however, some objects in the Wolfram System that have builtin upvalues. For example, SeriesData objects, which represent power series, have builtin 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:
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":
Here is a general rule for composition, associated with comp:
If you compose two q objects, the rule associated with q is used:
If you compose r objects, the general rule associated with comp is used:
In general, there can be several objects that have upvalues in a particular expression. The Wolfram System 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. The Wolfram System 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:
This defines an upvalue for q:
Which upvalue is used depends on which occurs first in the sequence of arguments to c:
NonStandard Evaluation
While most builtin Wolfram Language functions follow the standard evaluation procedure, some important ones do not. For example, most of the Wolfram Language functions associated with the construction and execution of programs use nonstandard evaluation procedures. In typical cases, the functions either never evaluate some of their arguments, or do so in a special way under their own control.
x=y
do not evaluate the lefthand side
If[p,a,b]
evaluate a if p is True, and b if it is False
Do[expr,{n}]
evaluate expr n times
Plot[f,{x,}]
evaluate f with a sequence of numerical values for x
Function[{x},body]
do not evaluate until the function is applied
Some functions that use nonstandard evaluation procedures.
When you give a definition such as a=1, the Wolfram Language does not evaluate the a that appears on the lefthand side. You can see that there would be trouble if the a was evaluated. The reason is that if you had previously set a=7, then evaluating a in the definition a=1 would put the definition into the nonsensical form 7=1.
In the standard evaluation procedure, each argument of a function is evaluated in turn. This is prevented by setting the attributes HoldFirst, HoldRest and HoldAll. These attributes make the Wolfram Language "hold" particular arguments in an unevaluated form.
HoldFirst
do not evaluate the first argument
HoldRest
evaluate only the first argument
HoldAll
evaluate none of the arguments
Attributes for holding function arguments in unevaluated form.
With the standard evaluation procedure, all arguments to a function are evaluated:
This assigns the attribute HoldFirst to h:
The first argument to h is now held in an unevaluated form:
When you use the first argument to h like this, it will get evaluated:
Builtin functions like Set carry attributes such as HoldFirst:
Even though a function may have attributes which specify that it should hold certain arguments unevaluated, you can always explicitly tell the Wolfram Language to evaluate those arguments by giving the arguments in the form Evaluate[arg].
Evaluate effectively overrides the HoldFirst attribute, and causes the first argument to be evaluated:
f[Evaluate[arg]]
evaluate arg immediately, even though attributes of f may specify that it should be held
Forcing the evaluation of function arguments.
By holding its arguments, a function can control when those arguments are evaluated. By using Evaluate, you can force the arguments to be evaluated immediately, rather than being evaluated under the control of the function. This capability is useful in a number of circumstances.
The Wolfram Language Set function holds its first argument, so the symbol a is not evaluated in this case:
You can make Set evaluate its first argument using Evaluate. In this case, the result is the object which is the value of a, namely b is set to 6:
b has now been set to 6:
In most cases, you want all expressions you give to the Wolfram Language to be evaluated. Sometimes, however, you may want to prevent the evaluation of certain expressions. For example, if you want to manipulate pieces of a Wolfram Language program symbolically, then you must prevent those pieces from being evaluated while you are manipulating them.
You can use the functions Hold and HoldForm to keep expressions unevaluated. These functions work simply by carrying the attribute HoldAll, which prevents their arguments from being evaluated. The functions provide "wrappers" inside which expressions remain unevaluated.
The difference between Hold[expr] and HoldForm[expr] is that in standard Wolfram Language output format, Hold is printed explicitly, while HoldForm is not. If you look at the full internal Wolfram Language form, you can however see both functions.
Hold maintains expressions in an unevaluated form:
HoldForm also keeps expressions unevaluated, but is invisible in standard Wolfram Language output format:
HoldForm is still present internally:
The function ReleaseHold removes Hold and HoldForm, so the expressions they contain get evaluated:
Hold[expr]
keep expr unevaluated
HoldComplete[expr]
keep expr unevaluated and prevent upvalues associated with expr from being used
HoldForm[expr]
keep expr unevaluated, and print without HoldForm
ReleaseHold[expr]
remove Hold and HoldForm in expr
Extract[expr,index,Hold]
get a part of expr, wrapping it with Hold to prevent evaluation
Functions for handling unevaluated expressions.
Parts of expressions are usually evaluated as soon as you extract them:
This extracts a part and immediately wraps it with Hold, so it does not get evaluated:
f[,Unevaluated[expr],]
give expr unevaluated as an argument to f
Temporary prevention of argument evaluation.
1+1 evaluates to 2, and Length[2] gives 0:
This gives the unevaluated form 1+1 as the argument of Length:
Unevaluated[expr] effectively works by temporarily giving a function an attribute like HoldFirst, and then supplying expr as an argument to the function.
SequenceHold
do not flatten out Sequence objects that appear as arguments
HoldAllComplete
treat all arguments as completely inert
Attributes for preventing other aspects of evaluation.
By setting the attribute HoldAll, you can prevent the Wolfram Language from evaluating the arguments of a function. But even with this attribute set, the Wolfram Language will still do some transformations on the arguments. By setting SequenceHold you can prevent it from flattening out Sequence objects that appear in the arguments. And by setting HoldAllComplete you can also inhibit the stripping of Unevaluated, and prevent the Wolfram Language from using any upvalues it finds associated with the arguments.
Evaluation in Patterns, Rules, and Definitions
There are a number of important interactions in the Wolfram Language between evaluation and pattern matching. The first observation is that pattern matching is usually done on expressions that have already been at least partly evaluated. As a result, it is usually appropriate that the patterns to which these expressions are matched should themselves be evaluated.
The fact that the pattern is evaluated means that it matches the expression given:
The righthand side of the /; condition is not evaluated until it is used during pattern matching:
There are some cases, however, where you may want to keep all or part of a pattern unevaluated. You can do this by wrapping the parts you do not want to evaluate with HoldPattern. In general, whenever HoldPattern[patt] appears within a pattern, this form is taken to be equivalent to patt for the purpose of pattern matching, but the expression patt is maintained unevaluated.
HoldPattern[patt]
equivalent to patt for pattern matching, with patt kept unevaluated
Preventing evaluation in patterns.
One application for HoldPattern is in specifying patterns which can apply to unevaluated expressions, or expressions held in an unevaluated form.
HoldPattern keeps the 1+1 from being evaluated, and allows it to match the 1+1 on the lefthand side of the /. operator:
Notice that while functions like Hold prevent evaluation of expressions, they do not affect the manipulation of parts of those expressions with /. and other operators.
This defines values for r whenever its argument is not an atomic object:
According to the definition, expressions like r[3] are left unchanged:
However, the pattern r[x_] is transformed according to the definition for r:
You need to wrap HoldPattern around r[x_] to prevent it from being evaluated:
As illustrated above, the lefthand sides of transformation rules such as lhs->rhs are usually evaluated immediately, since the rules are usually applied to expressions which have already been evaluated. The righthand side of lhs->rhs is also evaluated immediately. With the delayed rule lhs:>rhs, however, the expression rhs is not evaluated.
The righthand side is evaluated immediately in -> but not :> rules:
Here are the results of applying the rules. The righthand side of the :> rule gets inserted inside the Hold without evaluation:
lhs->rhs
evaluate both lhs and rhs
lhs:>rhs
evaluate lhs but not rhs
Evaluation in transformation rules.
While the lefthand sides of transformation rules are usually evaluated, the lefthand sides of definitions are usually not. The reason for the difference is as follows. Transformation rules are typically applied using /. to expressions that have already been evaluated. Definitions, however, are used during the evaluation of expressions, and are applied to expressions that have not yet been completely evaluated. To work on such expressions, the lefthand sides of definitions must be maintained in a form that is at least partially unevaluated.
Definitions for symbols are the simplest case. As discussed in "NonStandard Evaluation", a symbol on the lefthand side of a definition such as x=value is not evaluated. If x had previously been assigned a value y, then if the lefthand side of x=value were evaluated, it would turn into the quite unrelated definition y=value.
Here is a definition. The symbol on the lefthand side is not evaluated:
This redefines the symbol:
If you evaluate the lefthand side, then you define not the symbol k, but the value w[4] of the symbol k:
Now w[4] has value w[5]:
Although individual symbols that appear on the lefthand sides of definitions are not evaluated, more complicated expressions are partially evaluated. In an expression such as f[args] on the lefthand side of a definition, the args are evaluated.
The 1+1 is evaluated, so that a value is defined for g[2]:
This shows the value defined for g:
You can see why the arguments of a function that appears on the lefthand side of a definition must be evaluated by considering how the definition is used during the evaluation of an expression. As discussed in "Principles of Evaluation", when the Wolfram Language evaluates a function, it first evaluates each of the arguments, then tries to find definitions for the function. As a result, by the time the Wolfram Language applies any definition you have given for a function, the arguments of the function must already have been evaluated. An exception to this occurs when the function in question has attributes which specify that it should hold some of its arguments unevaluated.
symbol=value
symbol is not evaluated; value is evaluated
symbol:=value
neither symbol nor value is evaluated
f[args]=value
args are evaluated; lefthand side as a whole is not
f[HoldPattern[arg]]=value
f [ arg ] is assigned, without evaluating arg
Evaluate[lhs]=value
lefthand side is evaluated completely
Evaluation in definitions.
While in most cases it is appropriate for the arguments of a function that appears on the lefthand side of a definition to be evaluated, there are some situations in which you do not want this to happen. In such cases, you can wrap HoldPattern around the parts that you do not want to be evaluated.
Evaluation in Iteration Functions
The builtin Wolfram Language iteration functions such as Table and Sum evaluate their arguments in a slightly special way.
When evaluating an expression like Table[f,{i,imax}], the first step, as discussed in "Blocks and Local Values", is to make the value of i local. Next, the limit imax in the iterator specification is evaluated. The expression f is maintained in an unevaluated form, but is repeatedly evaluated as a succession of values are assigned to i. When this is finished, the global value of i is restored.
The function RandomReal[] is evaluated four separate times here, so four different pseudorandom numbers are generated:
This evaluates RandomReal[] before feeding it to Table. The result is a list of four identical numbers:
In most cases, it is convenient for the function f in an expression like Table[f,{i,imax}] to be maintained in an unevaluated form until specific values have been assigned to i. This is true in particular if a complete symbolic form for f valid for any i cannot be found.
This defines fac to give the factorial when it has an integer argument, and to give NaN (standing for "Not a Number") otherwise:
In this form, fac[i] is not evaluated until an explicit integer value has been assigned to i:
Using Evaluate forces fac[i] to be evaluated with i left as a symbolic object:
In cases where a complete symbolic form for f with arbitrary i in expressions such as Table[f,{i,imax}] can be found, it is often more efficient to compute this form first, and then feed it to Table. You can do this using Table[Evaluate[f],{i,imax}].
The Sum in this case is evaluated separately for each value of i:
It is however possible to get a symbolic formula for the sum, valid for any value of i:
By inserting Evaluate, you tell the Wolfram Language first to evaluate the sum symbolically, then to iterate over i:
Table[f,{i,imax}]
keep f unevaluated until specific values are assigned to i
Table[Evaluate[f],{i,imax}]
evaluate f first with i left symbolic
Evaluation in iteration functions.
Conditionals
The Wolfram Language provides various ways to set up conditionals, which specify that particular expressions should be evaluated only if certain conditions hold.
lhs:=rhs/;test
use the definition only if test evaluates to True
If[test,then,else]
evaluate then if test is True, and else if it is False
Which[test1,value1,test2,]
evaluate the testi in turn, giving the value associated with the first one that is True
Switch[expr,form1,value1,form2,]
compare expr with each of the formi, giving the value associated with the first form it matches
Switch[expr,form1,value1,form2,,_,def]
use def as a default value
Piecewise[{{value1,test1},},def]
give the value corresponding to the first testi which yields True
Conditional constructs.
The test gives False, so the "else" expression y is returned:
Only the "else" expression is evaluated in this case:
When you write programs in the Wolfram Language, you will often have a choice between making a single definition whose righthand side involves several branches controlled by If functions, or making several definitions, each controlled by an appropriate /; condition. By using several definitions, you can often produce programs that are both clearer, and easier to modify.
This defines a step function, with value 1 for x>0, and -1 otherwise:
This defines the positive part of the step function using a /; condition:
Here is the negative part of the step function:
This shows the complete definition using /; conditions:
The function If provides a way to choose between two alternatives. Often, however, there will be more than two alternatives. One way to handle this is to use a nested set of If functions. Usually, however, it is instead better to use functions like Which and Switch.
This defines a function with three regions. Using True as the third test makes this the default case:
This uses the first case in the Which:
This uses the third case:
This defines a function that depends on the values of its argument modulo 3:
Mod[7,3] is 1, so this uses the second case in the Switch:
17 matches neither 0 nor 1, but does match _:
An important point about symbolic systems such as the Wolfram Language is that the conditions you give may yield neither True nor False. Thus, for example, the condition x==y does not yield True or False unless x and y have specific values, such as numerical ones.
In this case, the test gives neither True nor False, so both branches in the If remain unevaluated:
You can add a special fourth argument to If, which is used if the test does not yield True or False:
If[test,then,else,unknown]
a form of If which includes the expression to use if test is neither True nor False
TrueQ[expr]
give True if expr is True, and False otherwise
lhs===rhs
or
SameQ[lhs,rhs]
give True if lhs and rhs are identical, and False otherwise
lhs=!=rhs
or
UnsameQ[lhs,rhs]
give True if lhs and rhs are not identical, and False otherwise
MatchQ[expr,form]
give True if the pattern form matches expr, and give False otherwise
Functions for dealing with symbolic conditions.
The Wolfram Language leaves this as a symbolic equation:
Unless expr is manifestly True, TrueQ[expr] effectively assumes that expr is False:
Unlike ==, === tests whether two expressions are manifestly identical. In this case, they are not:
The main difference between lhs===rhs and lhs==rhs is that === always returns True or False, whereas == can leave its input in symbolic form, representing a symbolic equation, as discussed in "Equations". You should typically use === when you want to test the structure of an expression, and == if you want to test mathematical equality. The Wolfram Language pattern matcher effectively uses === to determine when one literal expression matches another.
You can use === to test the structure of expressions:
The == operator gives a less useful result:
In setting up conditionals, you will often need to use combinations of tests, such as test1&&test2&&. An important point is that the result from this combination of tests will be False if any of the testi yield False. The Wolfram Language always evaluates the testi in turn, stopping if any of the testi yield False.
expr1&&expr2&&expr3
evaluate until one of the expri is found to be False
expr1||expr2||expr3
evaluate until one of the expri is found to be True
Evaluation of logical expressions.
This function involves a combination of two tests:
Here both tests are evaluated:
Here the first test yields False, so the second test is not tried. The second test would involve 1/0, and would generate an error:
The way that the Wolfram Language evaluates logical expressions allows you to combine sequences of tests where later tests may make sense only if the earlier ones are satisfied. The behavior, which is analogous to that found in languages such as C, is convenient in constructing many kinds of Wolfram Language programs.
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".
Do[expr,{i,imax}]
evaluate expr repetitively, with i varying from 1 to imax in steps of 1
Do[expr,{i,imin,imax,di}]
evaluate expr with i varying from imin to imax in steps of di
Do[expr,{i,list}]
evaluate expr with i taking on values from list
Do[expr,{n}]
evaluate expr n times
Simple looping constructs.
This evaluates Print[i^2], with i running from 1 to 4:
This executes an assignment for t in a loop with k running from 2 to 6 in steps of 2:
The way iteration is specified in Do is exactly the same as in functions like Table and Sum. Just as in those functions, you can set up several nested loops by giving a sequence of iteration specifications to 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:
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 Do just as you can in Table and other iteration functions.
This repeats the assignment t=1/(1+t) three times:
You can put a procedure inside Do:
Nest[f,expr,n]
apply f to expr n times
FixedPoint[f,expr]
start with expr, and apply f repeatedly until the result no longer changes
NestWhile[f,expr,test]
start with expr, and apply f repeatedly until applying test to the result no longer yields True
Applying functions repetitively.
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". Nest[f,x,n], for example, allows you to apply a function repeatedly to an expression.
This nests f three times:
By nesting a pure function, you can get the same result as in the example with Do above:
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 FixedPoint[f,x].
FixedPoint goes on applying a function until the result no longer changes:
You can use FixedPoint to imitate the evaluation process in the Wolfram Language, or the operation of functions such as expr//.rules. FixedPoint goes on until two successive results it gets are the same. NestWhile allows you to go on until an arbitrary function no longer yields True.
Catch[expr]
evaluate expr until Throw[value] is encountered, then return value
Catch[expr,form]
evaluate expr until Throw[value,tag] is encountered, where form matches tag
Catch[expr,form,f]
return f[value,tag] instead of value
Nonlocal control of evaluation.
When the Throw is encountered, evaluation stops, and the current value of i is returned as the value of the enclosing Catch:
Throw and Catch provide a flexible way to control the process of evaluation in the Wolfram Language. The basic idea is that whenever a Throw is encountered, the evaluation that is then being done is stopped, and the Wolfram Language immediately returns to the nearest appropriate enclosing Catch.
Scan applies the function Print to each successive element in the list, and in the end just returns Null:
The evaluation of Scan stops as soon as Throw is encountered, and the enclosing Catch returns as its value the argument of Throw:
The same result is obtained with Map, even though Map would have returned a list if its evaluation had not been stopped by encountering a Throw:
You can use Throw and 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 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:
Since there is no Throw encountered, the result here is just as before:
Now the evaluation of the NestList is diverted, and the single number given as the argument of Throw is returned:
Throw and Catch operate in a completely global way: it does not matter how or where a Throw is generatedit will always stop evaluation and return to the enclosing Catch.
The Throw stops the evaluation of f, and causes the Catch to return just a, with no trace of f left:
This defines a function which generates a Throw when its argument is larger than 10:
No Throw is generated here:
But here the Throw generated inside the evaluation of g returns to the enclosing Catch:
In small programs, it is often adequate to use Throw[value] and 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 Throw[value,tag] and Catch[expr,form]. By keeping the expressions tag and form local to a particular piece of your program, you can then ensure that your Throw and Catch will also operate only within that piece.
Here the Throw is caught by the inner Catch:
But here it is caught only by the outer Catch:
You can use patterns in specifying the tags which a particular Catch should catch:
This keeps the tag a completely local:
You should realize that there is no need for the tag that appears in Throw to be a constant; in general it can be any expression.
Here the inner Catch catches all throws with tags less than 4, and continues the Do. But as soon as the tag reaches 4, the outer Catch is needed:
When you use Catch[expr,form] with Throw[value,tag], the value returned by Catch is simply the expression value given in the Throw. If you use Catch[expr,form,f], however, then the value returned by Catch is instead f[value,tag].
Here f is applied to the value and tag in the Throw:
If there is no Throw, f is never used:
While[test,body]
evaluate body repetitively, so long as test is True
For[start,test,incr,body]
evaluate start, then repetitively evaluate body and incr, until test fails
General loop constructs.
Functions like Do, Nest, and FixedPoint provide structured ways to make loops in Wolfram Language programs, while Throw and 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 While and For, which perform operations repeatedly, stopping when a specified condition fails to be true.
The While loop continues until the condition fails:
The functions While and 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 For loops relative to C language ones.
This is a very common form for a For loop. i++ increments the value of i:
Here is a more complicated For loop. Notice that the loop terminates as soon as the test i^2<10 fails:
In the Wolfram Language, both While and For always evaluate the loop test before evaluating the body of the loop. As soon as the loop test fails to be True, While and For terminate. The body of the loop is thus only evaluated in situations where the loop test is True.
The loop test fails immediately, so the body of the loop is never evaluated:
In a While or 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. While and 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 Throw and Catch. But the Wolfram Language also provides various functions for modifying the flow of control which work like in languages such as C.
Break[]
exit the nearest enclosing loop
Continue[]
go to the next step in the current loop
Return[expr]
return the value expr from a function
Goto[name]
go to the element Label[name] in the current procedure
Throw[value]
return value as the value of the nearest enclosing Catch (nonlocal return)
Control flow functions.
The Break[] causes the loop to terminate as soon as t exceeds 19:
When k<3, the Continue[] causes the loop to be continued, without executing t+=2:
Return[expr] allows you to exit a particular function, returning a value. You can think of 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 Return. This particular procedure could equally well have been written without using Return:
When the argument is greater than 5, the first Return in the procedure is used:
This function "throws" error if its argument is negative:
No Throw is generated here:
But in this case a Throw is generated, and the whole Catch returns the value error:
Functions like Continue[] and 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 Label as an element in a procedure, you can use Goto to transfer control to this element.
This goes on looping until q exceeds 6:
Note that you can use Goto in a particular Wolfram Language procedure only when the Label it specifies occurs as an element of the same Wolfram Language procedure. In general, use of 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.
Collecting Expressions during Evaluation
In many computations you are concerned only with the final result of evaluating the expression given as input. But sometimes you also want to collect expressions that were generated in the course of the evaluation. You can do this using Sow and Reap.
Sow[val]
sow the value val for the nearest enclosing Reap
Reap[expr]
evaluate expr, returning also a list of values sown by Sow
Using Sow and Reap.
Here the output contains only the final result:
Here two intermediate results are also given:
This computes a sum, collecting all terms that are even:
Like Throw and Catch, Sow and Reap can be used anywhere in a computation.
This defines a function that can do a Sow:
This nests the function, reaping all cases below 1/2:
Sow[val,tag]
sow val with a tag to indicate when to reap
Sow[val,{tag1,tag2,}]
sow val for each of the tagi
Reap[expr,form]
reap all values whose tags match form
Reap[expr,{form1,form2,}]
make separate lists for each of the formi
Reap[expr,{form1,},f]
apply f to each distinct tag and list of values
Sowing and reaping with tags.
This reaps only values sown with tag x:
Here 1 is sown twice with tag x:
Values sown with different tags always appear in different sublists:
This makes a sublist for each form of tag being reaped:
This applies f to each distinct tag and list of values:
The tags can be part of the computation:
Tracing Evaluation
The standard way in which the Wolfram System works is to take any expression you give as input, evaluate the expression completely, and then return the result. When you are trying to understand what the Wolfram System is doing, however, it is often worthwhile to look not just at the final result of evaluation, but also at intermediate steps in the evaluation process.
Trace[expr]
generate a list of all expressions used in the evaluation of expr
Trace[expr,form]
include only expressions that match the pattern form
Tracing the evaluation of expressions.
The expression 1+1 is evaluated immediately to 2:
The 2^3 is evaluated before the addition is done:
The evaluation of each subexpression is shown in a separate sublist:
Trace[expr] gives a list that includes all the intermediate expressions involved in the evaluation of expr. Except in rather simple cases, however, the number of intermediate expressions generated in this way is typically very large, and the list returned by Trace is difficult to understand.
Trace[expr,form] allows you to "filter" the expressions that Trace records, keeping only those that match the pattern form.
Here is a recursive definition of a factorial function:
This gives all the intermediate expressions generated in the evaluation of fac[3]. The result is quite complicated:
This shows only intermediate expressions of the form fac[n_]:
You can specify any pattern in Trace:
Trace[expr,form] effectively works by intercepting every expression that is about to be evaluated during the evaluation of expr, and picking out those that match the pattern form.
If you want to trace "calls" to a function like fac, you can do so simply by telling Trace to pick out expressions of the form fac[n_]. You can also use patterns like f[n_,2] to pick out calls with particular argument structure.
A typical Wolfram System program, however, consists not only of "function calls" like fac[n], but also of other elements, such as assignments to variables, control structures, and so on. All of these elements are represented as expressions. As a result, you can use patterns in Trace to pick out any kind of Wolfram System program element. Thus, for example, you can use a pattern like k=_ to pick out all assignments to the symbol k.
This shows the sequence of assignments made for k:
Trace[expr,form] can pick out expressions that occur at any time in the evaluation of expr. The expressions need not, for example, appear directly in the form of expr that you give. They may instead occur, say, during the evaluation of functions that are called as part of the evaluation of expr.
Here is a function definition:
You can look for expressions generated during the evaluation of h:
Trace allows you to monitor intermediate steps in the evaluation not only of functions that you define, but also of some functions that are built into the Wolfram System. You should realize, however, that the specific sequence of intermediate steps followed by builtin Wolfram System functions depends in detail on their implementation and optimization in a particular version of the Wolfram System.
Trace[expr,f[___]]
show all calls to the function f
Trace[expr,i=_]
show assignments to i
Trace[expr,_=_]
show all assignments
Trace[expr,Message[___]]
show messages generated
Some ways to use Trace.
The function Trace returns a list that represents the "history" of a Wolfram System computation. The expressions in the list are given in the order that they were generated during the computation. In most cases, the list returned by Trace has a nested structure, which represents the "structure" of the computation.
The basic idea is that each sublist in the list returned by Trace represents the "evaluation chain" for a particular Wolfram System expression. The elements of this chain correspond to different forms of the same expression. Usually, however, the evaluation of one expression requires the evaluation of a number of other expressions, often subexpressions. Each subsidiary evaluation is represented by a sublist in the structure returned by Trace.
Here is a sequence of assignments:
This yields an evaluation chain reflecting the sequence of transformations for a[i] used:
The successive forms generated in the simplification of y+x+y show up as successive elements in its evaluation chain:
Each argument of the function f has a separate evaluation chain, given in a sublist:
The evaluation chain for each subexpression is given in a separate sublist:
Tracing the evaluation of a nested expression yields a nested list:
There are two basic ways that subsidiary evaluations can be required during the evaluation of a Wolfram System expression. The first way is that the expression may contain subexpressions, each of which has to be evaluated. The second way is that there may be rules for the evaluation of the expression that involve other expressions that themselves must be evaluated. Both kinds of subsidiary evaluations are represented by sublists in the structure returned by Trace.
The subsidiary evaluations here come from evaluation of the arguments of f and g:
Here is a function with a condition attached:
The evaluation of fe[6] involves a subsidiary evaluation associated with the condition:
You often get nested lists when you trace the evaluation of functions that are defined "recursively" in terms of other instances of themselves. The reason is typically that each new instance of the function appears as a subexpression in the expressions obtained by evaluating previous instances of the function.
Thus, for example, with the definition fac[n_]:=n fac[n-1], the evaluation of fac[6] yields the expression 6 fac[5], which contains fac[5] as a subexpression.
The successive instances of fac generated appear in successively nested sublists:
With this definition, fp[n-1] is obtained directly as the value of fp[n]:
fp[n] never appears in a subexpression, so no sublists are generated:
Here is the recursive definition of the Fibonacci numbers:
Here are the end conditions for the recursion:
This shows all the steps in the recursive evaluation of fib[5]:
Each step in the evaluation of any Wolfram System expression can be thought of as the result of applying a particular transformation rule. As discussed in "Associating Definitions with Different Symbols", all the rules that the Wolfram System knows are associated with specific symbols or "tags". You can use Trace[expr,f] to see all the steps in the evaluation of expr that are performed using transformation rules associated with the symbol f. In this case, Trace gives not only the expressions to which each rule is applied, but also the results of applying the rules.
In general, Trace[expr,form] picks out all the steps in the evaluation of expr where form matches either the expression about to be evaluated, or the tag associated with the rule used.
Trace[expr,f]
show all evaluations that use transformation rules associated with the symbol f
Trace[expr,f|g]
show all evaluations associated with either f or g
Tracing evaluations associated with particular tags.
This shows only intermediate expressions that match fac[_]:
This shows all evaluations that use transformation rules associated with the symbol fac:
Here is a rule for the log function:
This traces the evaluation of log[abcd], showing all transformations associated with log:
Trace[expr,form,TraceOn->oform]
switch on tracing only within forms matching oform
Trace[expr,form,TraceOff->oform]
switch off tracing within any form matching oform
Switching off tracing inside certain forms.
Trace[expr,form] allows you to trace expressions matching form generated at any point in the evaluation of expr. Sometimes, you may want to trace only expressions generated during certain parts of the evaluation of expr.
By setting the option TraceOn->oform, you can specify that tracing should be done only during the evaluation of forms that match oform. Similarly, by setting TraceOff->oform, you can specify that tracing should be switched off during the evaluation of forms that match oform.
This shows all steps in the evaluation:
This shows only those steps that occur during the evaluation of fac:
This shows only those steps that do not occur during the evaluation of fac:
Trace[expr,lhs->rhs]
find all expressions matching lhs that arise during the evaluation of expr, and replace them with rhs
Applying rules to expressions encountered during evaluation.
This tells Trace to return only the arguments of fib used in the evaluation of fib[5]:
A powerful aspect of the Wolfram System Trace function is that the object it returns is basically a standard Wolfram System expression that you can manipulate using other Wolfram System functions. One important point to realize, however, is that Trace wraps all expressions that appear in the list it produces with HoldForm to prevent them from being evaluated. The HoldForm is not displayed in standard Wolfram System output format, but it is still present in the internal structure of the expression.
This shows the expressions generated at intermediate stages in the evaluation process:
The expressions are wrapped with HoldForm to prevent them from evaluating:
In standard Wolfram System output format, it is sometimes difficult to tell which lists are associated with the structure returned by Trace, and which are expressions being evaluated:
Looking at the input form resolves any ambiguities:
When you use a transformation rule in Trace, the result is evaluated before being wrapped with HoldForm:
For sophisticated computations, the list structures returned by Trace can be quite complicated. When you use Trace[expr,form], Trace will include as elements in the lists only those expressions that match the pattern form. But whatever pattern you give, the nesting structure of the lists remains the same.
This shows all occurrences of fib[_] in the evaluation of fib[3]:
This shows only occurrences of fib[1], but the nesting of the lists is the same as for fib[_]:
You can set the option TraceDepth->n to tell Trace to include only lists nested at most n levels deep. In this way, you can often pick out the "big steps" in a computation, without seeing the details. Note that by setting TraceDepth or TraceOff you can avoid looking at many of the steps in a computation, and thereby significantly speed up the operation of Trace for that computation.
This shows only steps that appear in lists nested at most two levels deep:
Trace[expr,form,TraceDepth->n]
trace the evaluation of expr, ignoring steps that lead to lists nested more than n levels deep
Restricting the depth of tracing.
When you use Trace[expr,form], you get a list of all the expressions that match form produced during the evaluation of expr. Sometimes it is useful to see not only these expressions, but also the results that were obtained by evaluating them. You can do this by setting the option TraceForward->True in Trace.
This shows not only expressions that match fac[_], but also the results of evaluating those expressions:
Expressions picked out using Trace[expr,form] typically lie in the middle of an evaluation chain. By setting TraceForward->True, you tell Trace to include also the expression obtained at the end of the evaluation chain. If you set TraceForward->All, Trace will include all the expressions that occur after the expression matching form on the evaluation chain.
With TraceForward->All, all elements on the evaluation chain after the one that matches fac[_] are included:
By setting the option TraceForward, you can effectively see what happens to a particular form of expression during an evaluation. Sometimes, however, you want to find out not what happens to a particular expression, but instead how that expression was generated. You can do this by setting the option TraceBackward. What TraceBackward does is to show you what preceded a particular form of expression on an evaluation chain.
This shows that the number 120 came from the evaluation of fac[5] during the evaluation of fac[10]:
Here is the whole evaluation chain associated with the generation of the number 120:
TraceForward and TraceBackward allow you to look forward and backward in a particular evaluation chain. Sometimes, you may also want to look at the evaluation chains within which the particular evaluation chain occurs. You can do this using TraceAbove. If you set the option TraceAbove->True, then Trace will include the initial and final expressions in all the relevant evaluation chains. With TraceAbove->All, Trace includes all the expressions in all these evaluation chains.
This includes the initial and final expressions in all evaluation chains that contain the chain that contains 120:
This shows all the ways that fib[2] is generated during the evaluation of fib[5]:
Trace[expr,form,opts]
trace the evaluation of expr using the specified options
TraceForward->True
include the final expression in the evaluation chain containing form
TraceForward->All
include all expressions following form in the evaluation chain
TraceBackward->True
include the first expression in the evaluation chain containing form
TraceBackward->All
include all expressions preceding form in the evaluation chain
TraceAbove->True
include the first and last expressions in all evaluation chains that contain the chain containing form
TraceAbove->All
include all expressions in all evaluation chains that contain the chain containing form
Option settings for including extra steps in trace lists.
The basic way that Trace[expr,] works is to intercept each expression encountered during the evaluation of expr, and then to use various criteria to determine whether this expression should be recorded. Normally, however, Trace intercepts expressions only after function arguments have been evaluated. By setting TraceOriginal->True, you can get Trace also to look at expressions before function arguments have been evaluated.
This includes expressions that match fac[_] both before and after argument evaluation:
The list structure produced by Trace normally includes only expressions that constitute steps in nontrivial evaluation chains. Thus, for example, individual symbols that evaluate to themselves are not normally included. Nevertheless, if you set TraceOriginal->True, then Trace looks at absolutely every expression involved in the evaluation process, including those that have trivial evaluation chains.
In this case, Trace includes absolutely all expressions, even those with trivial evaluation chains:
option name
default value
TraceForwardFalse
whether to show expressions following form in the evaluation chain
TraceBackwardFalse
whether to show expressions preceding form in the evaluation chain
TraceAboveFalse
whether to show evaluation chains leading to the evaluation chain containing form
TraceOriginalFalse
whether to look at expressions before their heads and arguments are evaluated
Additional options for Trace.
When you use Trace to study the execution of a program, there is an issue about how local variables in the program should be treated. As discussed in "How Modules Work", Wolfram System scoping constructs such as Module create symbols with new names to represent local variables. Thus, even if you called a variable x in the original code for your program, the variable may effectively be renamed x$nnn when the program is executed.
Trace[expr,form] is set up so that by default a symbol x that appears in form will match all symbols with names of the form x$nnn that arise in the execution of expr. As a result, you can for example use Trace[expr,x=_] to trace assignment to all variables, local and global, that were named x in your original program.
Trace[expr,form,MatchLocalNames->False]
include all steps in the execution of expr that match form, with no replacements for local variable names allowed
Preventing the matching of local variables.
In some cases, you may want to trace only the global variable x, and not any local variables that were originally named x. You can do this by setting the option MatchLocalNames->False.
This traces assignments to all variables with names of the form x$nnn:
This traces assignments only to the specific global variable x:
The function Trace performs a complete computation, then returns a structure that represents the history of the computation. Particularly in very long computations, it is however sometimes useful to see traces of the computation as it proceeds. The function TracePrint works essentially like Trace, except that it prints expressions when it encounters them, rather than saving up all of the expressions to create a list structure.
This prints expressions encountered in the evaluation of fib[3]:
The sequence of expressions printed by TracePrint corresponds to the sequence of expressions given in the list structure returned by Trace. Indentation in the output from TracePrint corresponds to nesting in the list structure from Trace. You can use the Trace options TraceOn, TraceOff and TraceForward in TracePrint. However, since TracePrint produces output as it goes, it cannot support the option TraceBackward. In addition, TracePrint is set up so that TraceOriginal is effectively always set to True.
Trace[expr,]
trace the evaluation of expr, returning a list structure containing the expressions encountered
TracePrint[expr,]
trace the evaluation of expr, printing the expressions encountered
TraceDialog[expr,]
trace the evaluation of expr, initiating a dialog when each specified expression is encountered
TraceScan[f,expr,]
trace the evaluation of expr, applying f to HoldForm of each expression encountered
Functions for tracing evaluation.
This enters a dialog when fac[5] is encountered during the evaluation of fac[10]:
Inside the dialog you can for example find out where you are by looking at the "stack":
This returns from the dialog, and gives the final result from the evaluation of fac[10]:
The function TraceDialog effectively allows you to stop in the middle of a computation and interact with the Wolfram System environment that exists at that time. You can, for example, find values of intermediate variables in the computation, and even reset those values. There are, however, a number of subtleties, mostly associated with pattern and module variables.
What TraceDialog does is to call the function Dialog on a sequence of expressions. The Dialog function is discussed in detail in "Dialogs". When you call Dialog, you are effectively starting a subsidiary Wolfram System session with its own sequence of input and output lines.
In general, you may need to apply arbitrary functions to the expressions you get while tracing an evaluation. TraceScan[f,expr,] applies f to each expression that arises. The expression is wrapped with HoldForm to prevent it from evaluating.
In TraceScan[f,expr,], the function f is applied to expressions before they are evaluated. TraceScan[f,expr,patt,fp] applies f before evaluation, and fp after evaluation.
The Evaluation Stack
Throughout any computation, the Wolfram System maintains an evaluation stack containing the expressions it is currently evaluating. You can use the function Stack to look at the stack. This means, for example, that if you interrupt the Wolfram System in the middle of a computation, you can use Stack to find out what the Wolfram System is doing.
The expression that the Wolfram System most recently started to evaluate always appears as the last element of the evaluation stack. The previous elements of the stack are the other expressions whose evaluation is currently in progress.
Thus at the point when x is being evaluated, the stack associated with the evaluation of an expression like f[g[x]] will have the form {f[g[x]],g[x],x}.
Stack[_] gives the expressions that are being evaluated at the time when it is called, in this case including the Print function:
Stack[] gives the tags associated with the evaluations that are being done when it is called:
In general, you can think of the evaluation stack as showing what functions called what other functions to get to the point the Wolfram System is at in your computation. The sequence of expressions corresponds to the first elements in the successively nested lists returned by Trace with the option TraceAbove set to True.
Stack[]
give a list of the tags associated with evaluations that are currently being done
Stack[_]
give a list of all expressions currently being evaluated
Stack[form]
include only expressions which match form
Looking at the evaluation stack.
It is rather rare to call Stack directly in your main Wolfram System session. More often, you will want to call Stack in the middle of a computation. Typically, you can do this from within a dialog, or subsidiary session, as discussed in "Dialogs".
Here is the standard recursive definition of the factorial function:
This evaluates fac[10], starting a dialog when it encounters fac[4]:
This shows what objects were being evaluated when the dialog was started:
This ends the dialog:
In the simplest cases, the Wolfram System evaluation stack is set up to record all expressions currently being evaluated. Under some circumstances, however, this may be inconvenient. For example, executing Print[Stack[]] will always show a stack with Print as the last function.
The function StackInhibit allows you to avoid this kind of problem. StackInhibit[expr] evaluates expr without modifying the stack.
StackInhibit prevents Print from being included on the stack:
Functions like TraceDialog automatically call StackInhibit each time they start a dialog. This means that Stack does not show functions that are called within the dialog, only those outside.
StackInhibit[expr]
evaluate expr without modifying the stack
StackBegin[expr]
evaluate expr with a fresh stack
StackComplete[expr]
evaluate expr with intermediate expressions in evaluation chains included on the stack
Controlling the evaluation stack.
By using StackInhibit and StackBegin, you can control which parts of the evaluation process are recorded on the stack. StackBegin[expr] evaluates expr, starting a fresh stack. This means that during the evaluation of expr, the stack does not include anything outside the StackBegin. Functions like TraceDialog[expr,] call StackBegin before they begin evaluating expr, so that the stack shows how expr is evaluated, but not how TraceDialog was called.
StackBegin[expr] uses a fresh stack in the evaluation of expr:
Stack normally shows you only those expressions that are currently being evaluated. As a result, it includes only the latest form of each expression. Sometimes, however, you may find it useful also to see earlier forms of the expressions. You can do this using StackComplete.
What StackComplete[expr] effectively does is to keep on the stack the complete evaluation chain for each expression that is currently being evaluated. In this case, the stack corresponds to the sequence of expressions obtained from Trace with the option TraceBackward->All as well as TraceAbove->True.
Controlling Infinite Evaluation
The general principle that the Wolfram Language follows in evaluating expressions is to go on applying transformation rules until the expressions no longer change. This means, for example, that if you make an assignment like x=x+1, the Wolfram Language should go into an infinite loop. In fact, the Wolfram Language stops after a definite number of steps, determined by the value of the global variable $RecursionLimit. You can always stop the Wolfram Language earlier by explicitly interrupting it.
This assignment could cause an infinite loop. The Wolfram Language stops after a number of steps determined by $RecursionLimit:
When the Wolfram Language stops without finishing evaluation, it returns a held result. You can continue the evaluation by explicitly calling ReleaseHold:
$RecursionLimit
maximum depth of the evaluation stack
$IterationLimit
maximum length of an evaluation chain
Global variables that limit infinite evaluation.
Here is a circular definition, whose evaluation is stopped by $IterationLimit:
The variables $RecursionLimit and $IterationLimit control the two basic ways that an evaluation can become infinite in the Wolfram Language. $RecursionLimit limits the maximum depth of the evaluation stack, or equivalently, the maximum nesting depth that would occur in the list structure produced by Trace. $IterationLimit limits the maximum length of any particular evaluation chain, or the maximum length of any single list in the structure produced by Trace.
$RecursionLimit and $IterationLimit are by default set to values that are appropriate for most computations, and most computer systems. You can, however, reset these variables to any integer (above a lower limit), or to Infinity. Note that on most computer systems, you should never set $RecursionLimit=Infinity, as discussed in "Memory Management".
This resets $RecursionLimit and $IterationLimit to 20:
Now infinite definitions like this are stopped after just 20 steps:
Without an end condition, this recursive definition leads to infinite computations:
A fairly large structure is built up before the computation is stopped:
Here is another recursive definition:
In this case, no complicated structure is built up, and the computation is stopped by $IterationLimit:
It is important to realize that infinite loops can take up not only time but also computer memory. Computations limited by $IterationLimit do not normally build up large intermediate structures. But those limited by $RecursionLimit often do. In many cases, the size of the structures produced is a linear function of the value of $RecursionLimit. But in some cases, the size can grow exponentially, or worse, with $RecursionLimit.
An assignment like x=x+1 is obviously circular. When you set up more complicated recursive definitions, however, it can be much more difficult to be sure that the recursion terminates, and that you will not end up in an infinite loop. The main thing to check is that the righthand sides of your transformation rules will always be different from the lefthand sides. This ensures that evaluation will always "make progress", and the Wolfram Language will not simply end up applying the same transformation rule to the same expression over and over again.
Some of the trickiest cases occur when you have rules that depend on complicated /; conditions (see "Putting Constraints on Patterns"). One particularly awkward case is when the condition involves a "global variable". The Wolfram Language may think that the evaluation is finished because the expression did not change. However, a side effect of some other operation could change the value of the global variable, and so should lead to a new result in the evaluation. The best way to avoid this kind of difficulty is not to use global variables in /; conditions. If all else fails, you can type Update[s] to tell the Wolfram Language to update all expressions involving s. Update[] tells the Wolfram Language to update absolutely all expressions.
Interrupts and Aborts
"Interrupting Calculations" describes how you can interrupt a Wolfram Language computation by pressing appropriate keys on your keyboard.
In some cases, you may want to simulate such interrupts from within a Wolfram Language program. In general, executing Interrupt[] has the same effect as pressing interrupt keys. On a typical system, a menu of options is displayed, as discussed in "Interrupting Calculations".
Interrupt[]
interrupt a computation
Abort[]
abort a computation
CheckAbort[expr,failexpr]
evaluate expr and return the result, or failexpr if an abort occurs
AbortProtect[expr]
evaluate expr, masking the effect of aborts until the evaluation is complete
Interrupts and aborts.
The function Abort[] has the same effect as interrupting a computation, and selecting the abort option in the interrupt menu.
You can use Abort[] to implement an "emergency stop" in a program. In almost all cases, however, you should try to use functions like Return and Throw, which lead to more controlled behavior.
Abort terminates the computation, so only the first Print is executed:
If you abort at any point during the evaluation of a Wolfram Language expression, the Wolfram Language normally abandons the evaluation of the whole expression, and returns the value $Aborted.
You can, however, "catch" aborts using the function CheckAbort. If an abort occurs during the evaluation of expr in CheckAbort[expr,failexpr], then CheckAbort returns failexpr, but the abort propagates no further. Functions like Dialog use CheckAbort in this way to contain the effect of aborts.
CheckAbort catches the abort, prints c and returns the value aborted:
The effect of the Abort is contained by CheckAbort, so b is printed:
When you construct sophisticated programs in the Wolfram Language, you may sometimes want to guarantee that a particular section of code in a program cannot be aborted, either interactively or by calling Abort. The function AbortProtect allows you to evaluate an expression, saving up any aborts until after the evaluation of the expression is complete.
The Abort is saved up until AbortProtect is finished:
The CheckAbort sees the abort, but does not propagate it further:
Even inside AbortProtect, CheckAbort will see any aborts that occur, and will return the appropriate failexpr. Unless this failexpr itself contains Abort[], the aborts will be "absorbed" by the CheckAbort.
Compiling Wolfram Language Expressions
If you make a definition like f[x_]:=x Sin[x], the Wolfram Language will store the expression x Sin[x] in a form that can be evaluated for any x. Then when you give a particular value for x, the Wolfram Language substitutes this value into x Sin[x], and evaluates the result. The internal code that the Wolfram Language uses to perform this evaluation is set up to work equally well whether the value you give for x is a number, a list, an algebraic object, or any other kind of expression.
Having to take account of all these possibilities inevitably makes the evaluation process slower. However, if the Wolfram Language could assume that x will be a machine number, then it could avoid many steps, and potentially evaluate an expression like x Sin[x] much more quickly.
Using Compile, you can construct compiled functions in the Wolfram Language, which evaluate Wolfram Language expressions assuming that all the parameters which appear are numbers (or logical variables). Compile[{x1,x2,},expr] takes an expression expr and returns a "compiled function" which evaluates this expression when given arguments .
In general, Compile creates a CompiledFunction object which contains a sequence of simple instructions for evaluating the compiled function. The instructions are chosen to be close to those found in the machine code of a typical computer, and can thus be executed quickly.
Compile[{x1,x2,},expr]
create a compiled function which evaluates expr for numerical values of the xi
Creating compiled functions.
This defines f to be a pure function which evaluates x Sin[x] for any x:
This creates a compiled function for evaluating x Sin[x]:
f and fc yield the same results, but fc runs faster when the argument you give is a number:
Compile is useful in situations where you have to evaluate a particular numerical or logical expression many times. By taking the time to call Compile, you can get a compiled function which can be executed more quickly than an ordinary Wolfram Language function.
For simple expressions such as x Sin[x], there is usually little difference between the execution speed for ordinary and compiled functions. However, as the size of the expressions involved increases, the advantage of compilation also increases. For large expressions, compilation can speed up execution by a factor as large as 20.
Compilation makes the biggest difference for expressions containing a large number of simple, say arithmetic, functions. For more complicated functions, such as BesselK or Eigenvalues, most of the computation time is spent executing internal Wolfram Language algorithms, on which compilation has no effect.
This creates a compiled function for finding values of the tenth Legendre polynomial. Evaluate tells the Wolfram Language to construct the polynomial explicitly before doing compilation:
This finds the value of the tenth Legendre polynomial with argument 0.4:
This uses builtin numerical code:
Even though you can use compilation to speed up numerical functions that you write, you should still try to use builtin Wolfram Language functions whenever possible. Builtin functions will usually run faster than any compiled Wolfram Language programs you can create. In addition, they typically use more extensive algorithms, with more complete control over numerical precision and so on.
You should realize that builtin Wolfram Language functions quite often themselves use Compile. Thus, for example, NIntegrate by default automatically uses Compile on the expression you tell it to integrate. Similarly, functions like Plot and Plot3D use Compile on the expressions you ask them to plot. Builtin functions that use Compile typically have the option Compiled. Setting Compiled->False tells the functions not to use Compile.
Compile[{{x1,t1},{x2,t2},},expr]
compile expr assuming that xi is of type ti
Compile[{{x1,t1,n1},{x2,t2,n2},},expr]
compile expr assuming that xi is a rank ni array of objects each of type ti
Compile[vars,expr,{{p1,pt1},}]
compile expr, assuming that subexpressions which match pi are of type pti
_Integer
machinesize integer
_Real
machineprecision approximate real number
_Complex
machineprecision approximate complex number
True|False
logical variable
Specifying types for compilation.
Compile works by making assumptions about the types of objects that occur in evaluating the expression you give. The default assumption is that all variables in the expression are approximate real numbers.
Compile nevertheless also allows integers, complex numbers and logical variables (True or False), as well as arrays of numbers. You can specify the type of a particular variable by giving a pattern which matches only values that have that type. Thus, for example, you can use the pattern _Integer to specify the integer type. Similarly, you can use True|False to specify a logical variable that must be either True or False.
This compiles the expression 5i+j with the assumption that i and j are integers:
This yields an integer result:
This compiles an expression that performs an operation on a matrix of integers:
The list operations are now carried out in a compiled way, and the result is an integer:
The types that Compile handles correspond essentially to the types that computers typically handle at a machinecode level. Thus, for example, Compile can handle approximate real numbers that have machine precision, but it cannot handle arbitraryprecision numbers. In addition, if you specify that a particular variable is an integer, Compile generates code only for the case when the integer is of "machine size", typically between .
When the expression you ask to compile involves only standard arithmetic and logical operations, Compile can deduce the types of objects generated at every step simply from the types of the input variables. However, if you call other functions, Compile will typically not know what type of value they return. If you do not specify otherwise, Compile assumes that any other function yields an approximate real number value. You can, however, also give an explicit list of patterns, specifying what type to assume for an expression that matches a particular pattern.
This defines a function which yields an integer result when given an integer argument:
This compiles x^com[i] using the assumption that com[_] is always an integer:
This evaluates the compiled function:
The idea of Compile is to create a function which is optimized for certain types of arguments. Compile is nevertheless set up so that the functions it creates work with whatever types of arguments they are given. When the optimization cannot be used, a standard Wolfram Language expression is evaluated to find the value of the function.
Here is a compiled function for taking the square root of a variable:
If you give a real number argument, optimized code is used:
The compiled code cannot be used, so the Wolfram Language prints a warning, then just evaluates the original symbolic expression:
The compiled code generated by Compile must make assumptions not only about the types of arguments you will supply, but also about the types of all objects that arise during the execution of the code. Sometimes these types depend on the actual values of the arguments you specify. Thus, for example, Sqrt[x] yields a real number result for real x if x is not negative, but yields a complex number if x is negative.
Compile always makes a definite assumption about the type returned by a particular function. If this assumption turns out to be invalid in a particular case when the code generated by Compile is executed, then the Wolfram Language simply abandons the compiled code in this case, and evaluates an ordinary Wolfram Language expression to get the result.
The compiled code does not expect a complex number, so the Wolfram Language has to revert to explicitly evaluating the original symbolic expression:
An important feature of Compile is that it can handle not only mathematical expressions, but also various simple Wolfram Language programs. Thus, for example, Compile can handle conditionals and control flow structures.
In all cases, Compile[vars,expr] holds its arguments unevaluated. This means that you can explicitly give a "program" as the expression to compile.
This creates a compiled version of a Wolfram Language program which implements Newton's approximation to square roots:
This executes the compiled code: