Movatterモバイル変換


[0]ホーム

URL:


WOLFRAM

Wolfram Language & System Documentation Center
Evaluation of Expressions

Evaluation of Expressions

Principles of Evaluation
The fundamental operation that the Wolfram Language performs isevaluation. 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 expression6+7 using a builtin procedure for adding integers. Similarly, the Wolfram Language evaluates the algebraic expressionx-3x+1 using a builtin simplification procedure. If you had made the definitionx=5, then the Wolfram Language would use this definition to reducex-3x+1 to-9.
The two most central concepts in the Wolfram Language are probablyexpressions andevaluation."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 aninfinite 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 definesx1 in terms ofx2, and then definesx2:
If you ask forx1, 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 forfac[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 forf[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 functionf:
With the new definition, the results you get can change:
The simplest examples of evaluation involve using definitions such asf[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 expressionPrint[zzzz] is evaluated three times during the evaluation of theDo 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 thePlus 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) anda+b+c are all equivalent. But for many purposes it is convenient for all these forms to be reduced to the single standard forma+b+c. The builtin definitions forPlus are set up to do this.
Through the builtin definitions forPlus, 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 likea+c+b anda+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 twof's cancel, leaving the result0:
You could imagine finding out whethera+c+b was equal toc+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 reduceall 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 thesame 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 functionExpand. 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 applyingFactor, 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 likeExpand andFactor 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 applyingExpand. 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 thesame standard form, you may wonder whether it is at leastpossible to reduce all expressions tosome 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 asf[x_]=x^2 specifyvalues for functions. Sometimes, however, you need to specify general properties of functions, without necessarily giving explicit values.
The Wolfram Language provides a selection ofattributes that you can use to specify various properties of functions. For example, you can use the attributeFlat 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 attributeFlat to the functionf:
Nowf behaves as a flat, or associative, function, so that nested invocations are automatically flattened:
Attributes likeFlat 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 functionf:
Becausef is flat, the definition is automatically applied to every subsequence of arguments:
Attributes[f]
give the attributes off
Attributes[f]={attr1,attr2,}
set the attributes off
Attributes[f]={}
setf to have no attributes
SetAttributes[f,attr]
addattr to the attributes off
ClearAttributes[f,attr]
removeattr from the attributes off
Manipulating attributes of symbols.
This shows the attributes assigned tof:
This removes the attributes assigned tof:
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 toa 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 off are zero
NumericFunction
f is assumed to have a numerical value when its arguments are numeric quantities
Protected
values off cannot be changed
Locked
attributes off cannot be changed
ReadProtected
values off cannot be read
HoldFirst
the first argument off is not evaluated
HoldRest
all but the first argument off are not evaluated
HoldAll
none of the arguments off are evaluated
HoldAllComplete
the arguments off are treated as completely inert
NHoldFirst
the first argument off is not affected byN
NHoldRest
all but the first argument off are not affected byN
NHoldAll
none of the arguments off are affected byN
SequenceHold
Sequence objects appearing in the arguments off are not flattened out
Temporary
f is a local variable, removed when no longer used
Stub
Needs is automatically called iff is ever explicitly input
The complete list of attributes for symbols in the Wolfram Language.
Here are the attributes for the builtin functionPlus:
An important attribute assigned to builtin mathematical functions in the Wolfram Language is the attributeListable. 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 builtinLog function isListable:
This defines the functionp to be listable:
Nowp 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 attributeOneIdentity affects only pattern matching, as discussed in"Flat and Orderless Functions". Similarly, the attributeConstant is only relevant in differentiation, and operations that rely on differentiation.
TheProtected attribute affects assignments. The Wolfram Language does not allow you to make any definition associated with a symbol that carries this attribute. The functionsProtect andUnprotect discussed in"Modifying Built-in Functions" can be used as alternatives toSetAttributes andClearAttributes 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 functiong:
This sets theProtected attribute forg:
Now you cannot modify the definition ofg:
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 attributeReadProtected, 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 ofg:
This sets theReadProtected attribute forg:
Now you can no longer read the definition ofg:
Functions likeSetAttributes andClearAttributes usually allow you to modify the attributes of a symbol in any way. However, if you once set theLocked 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 theLocked attribute in addition toProtected orReadProtected, you can arrange for it to be impossible for users to modify or read definitions.
Clear[f]
remove values forf, but not attributes
ClearAll[f]
remove both values and attributes off
Clearing values and attributes.
This clears values and attributes ofp which was given attributeListable above:
Nowp 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 callingThread, you can implement the transformation that would be done automatically ifp were listable:
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 attributesattr1,
Pure functions with attributes.
This pure function appliesp to the whole list:
By adding the attributeListable, the function gets distributed over the elements of the list before applyingp:
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 threePrint functions are evaluated in turn, each printing its argument, then returning the valueNull:
This assigns the symbolps to bePlus:
The headps 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 attributesOrderless,Flat, orListable, 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 attributesOrderless,Listable, andFlat.
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 thata=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 forTimes give this result
Power[a,2]
this is evaluated next
Power[7,2]
here is the result after evaluatinga
49
builtin definitions forPower give this result
Plus[Times[14,x],49,1]
here is the result after the arguments ofPlus have been evaluated
Plus[50,Times[14,x]]
builtin definitions forPlus 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 functionTrace[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 ofTrace.)
First seta to7:
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 forArcSin:
You can give your own definitions forArcSin. 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 likef[g[x]], there are, in general, two sets of definitions that could apply: downvalues associated withf and upvalues associated withg. The Wolfram System tries the definitions associated withg before those associated withf.
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 forf[g[x_]], to be associated withf:
This defines a rule forf[g[x_]], to be associated withg:
The rule associated withg is tried before the rule associated withf:
If you remove rules associated withg, the rule associated withf is used:
Definitions associated withg are applied before definitions associated withf in the expressionf[g[x]].
The order in which definitions are applied.
Most functions such asPlus 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 likef[g[x]], the complete sequence of definitions that are tried in the standard evaluation procedure is:
  • Definitions you have given associated withg;
  • Builtin definitions associated withg;
  • Definitions you have given associated withf;
  • Builtin definitions associated withf.
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 withq for composition of "q objects":
Here is a general rule for composition, associated withcomp:
If you compose twoq objects, the rule associated withq is used:
If you composer objects, the general rule associated withcomp 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 forp with respect toc:
This defines an upvalue forq:
Which upvalue is used depends on which occurs first in the sequence of arguments toc:
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]
evaluatea ifp isTrue, andb if it isFalse
Do[expr,{n}]
evaluateexprn times
Plot[f,{x,}]
evaluatef with a sequence of numerical values forx
Function[{x},body]
do not evaluate until the function is applied
Some functions that use nonstandard evaluation procedures.
When you give a definition such asa=1, the Wolfram Language does not evaluate thea that appears on the lefthand side. You can see that there would be trouble if thea was evaluated. The reason is that if you had previously seta=7, then evaluatinga in the definitiona=1 would put the definition into the nonsensical form7=1.
In the standard evaluation procedure, each argument of a function is evaluated in turn. This is prevented by setting the attributesHoldFirst,HoldRest andHoldAll. 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 attributeHoldFirst to h:
The first argument toh is now held in an unevaluated form:
When you use the first argument toh like this, it will get evaluated:
Builtin functions likeSet carry attributes such asHoldFirst:
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 formEvaluate[arg].
Evaluate effectively overrides theHoldFirst attribute, and causes the first argument to be evaluated:
f[Evaluate[arg]]
evaluatearg immediately, even though attributes off 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 usingEvaluate, 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 LanguageSet function holds its first argument, so the symbola is not evaluated in this case:
You can makeSet evaluate its first argument usingEvaluate. In this case, the result is the object which is thevalue ofa, namelyb is set to6:
b has now been set to6:
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 functionsHold andHoldForm to keep expressions unevaluated. These functions work simply by carrying the attributeHoldAll, which prevents their arguments from being evaluated. The functions provide "wrappers" inside which expressions remain unevaluated.
The difference betweenHold[expr] andHoldForm[expr] is that in standard Wolfram Language output format,Hold is printed explicitly, whileHoldForm 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 functionReleaseHold removesHold andHoldForm, so the expressions they contain get evaluated:
Hold[expr]
keepexpr unevaluated
HoldComplete[expr]
keepexpr unevaluated and prevent upvalues associated withexpr from being used
HoldForm[expr]
keepexpr unevaluated, and print withoutHoldForm
ReleaseHold[expr]
removeHold andHoldForm inexpr
Extract[expr,index,Hold]
get a part ofexpr, wrapping it withHold 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 withHold, so it does not get evaluated:
f[,Unevaluated[expr],]
giveexpr unevaluated as an argument tof
Temporary prevention of argument evaluation.
1+1 evaluates to2, andLength[2] gives0:
This gives the unevaluated form1+1 as the argument ofLength:
Unevaluated[expr] effectively works by temporarily giving a function an attribute likeHoldFirst, and then supplyingexpr as an argument to the function.
SequenceHold
do not flatten outSequence objects that appear as arguments
HoldAllComplete
treat all arguments as completely inert
Attributes for preventing other aspects of evaluation.
By setting the attributeHoldAll, 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 settingSequenceHold you can prevent it from flattening outSequence objects that appear in the arguments. And by settingHoldAllComplete you can also inhibit the stripping ofUnevaluated, 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 withHoldPattern. In general, wheneverHoldPattern[patt] appears within a pattern, this form is taken to be equivalent topatt for the purpose of pattern matching, but the expressionpatt is maintained unevaluated.
HoldPattern[patt]
equivalent topatt for pattern matching, withpatt kept unevaluated
Preventing evaluation in patterns.
One application forHoldPattern is in specifying patterns which can apply to unevaluated expressions, or expressions held in an unevaluated form.
HoldPattern keeps the1+1 from being evaluated, and allows it to match the1+1 on the lefthand side of the/. operator:
Notice that while functions likeHold prevent evaluation of expressions, they do not affect the manipulation of parts of those expressions with/. and other operators.
This defines values forr whenever its argument is not an atomic object:
According to the definition, expressions liker[3] are left unchanged:
However, the patternr[x_] is transformed according to the definition forr:
You need to wrapHoldPattern aroundr[x_] to prevent it from being evaluated:
As illustrated above, the lefthand sides of transformation rules such aslhs->rhs are usually evaluated immediately, since the rules are usually applied to expressions which have already been evaluated. The righthand side oflhs->rhs is also evaluated immediately. With the delayed rulelhs:>rhs, however, the expressionrhs 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 theHold without evaluation:
lhs->rhs
evaluate bothlhs andrhs
lhs:>rhs
evaluatelhs but notrhs
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 asx=value is not evaluated. Ifx had previously been assigned a valuey, then if the lefthand side ofx=value were evaluated, it would turn into the quite unrelated definitiony=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 symbolk, but thevaluew[4] of the symbolk:
Noww[4] has valuew[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 asf[args] on the lefthand side of a definition, theargs are evaluated.
The1+1 is evaluated, so that a value is defined forg[2]:
This shows the value defined forg:
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
neithersymbol norvalue is evaluated
f[args]=value
args are evaluated; lefthand side as a whole is not
f[HoldPattern[arg]]=value
f[arg] is assigned, without evaluatingarg
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 wrapHoldPattern around the parts that you do not want to be evaluated.
Evaluation in Iteration Functions
The builtin Wolfram Language iteration functions such asTable andSum evaluate their arguments in a slightly special way.
When evaluating an expression likeTable[f,{i,imax}], the first step, as discussed in "Blocks and Local Values", is to make the value ofi local. Next, the limitimax in the iterator specification is evaluated. The expressionf is maintained in an unevaluated form, but is repeatedly evaluated as a succession of values are assigned toi. When this is finished, the global value ofi is restored.
The functionRandomReal[] is evaluated four separate times here, so four different pseudorandom numbers are generated:
This evaluatesRandomReal[] before feeding it toTable. The result is a list of four identical numbers:
In most cases, it is convenient for the functionf in an expression likeTable[f,{i,imax}] to be maintained in an unevaluated form until specific values have been assigned toi. This is true in particular if a complete symbolic form forf valid for anyi cannot be found.
This definesfac to give the factorial when it has an integer argument, and to giveNaN (standing for "Not a Number") otherwise:
In this form,fac[i] is not evaluated until an explicit integer value has been assigned toi:
UsingEvaluate forcesfac[i] to be evaluated withi left as a symbolic object:
In cases where a complete symbolic form forf with arbitraryi in expressions such asTable[f,{i,imax}]can be found, it is often more efficient to compute this form first, and then feed it toTable. You can do this usingTable[Evaluate[f],{i,imax}].
TheSum in this case is evaluated separately for each value ofi:
It is however possible to get a symbolic formula for the sum, valid for any value ofi:
By insertingEvaluate, you tell the Wolfram Language first to evaluate the sum symbolically, then to iterate overi:
Table[f,{i,imax}]
keepf unevaluated until specific values are assigned toi
Table[Evaluate[f],{i,imax}]
evaluatef first withi left symbolic
Evaluation in iteration functions.
Conditionals
The Wolfram Language provides various ways to set upconditionals, which specify that particular expressions should be evaluated only if certain conditions hold.
lhs:=rhs/;test
use the definition only iftest evaluates toTrue
If[test,then,else]
evaluatethen iftest isTrue, andelse if it isFalse
Which[test1,value1,test2,]
evaluate thetesti in turn, giving the value associated with the first one that isTrue
Switch[expr,form1,value1,form2,]
compareexpr with each of theformi, giving the value associated with the first form it matches
Switch[expr,form1,value1,form2,,_,def]
usedef as a default value
Piecewise[{{value1,test1},},def]
give the value corresponding to the firsttesti which yieldsTrue
Conditional constructs.
The test givesFalse, so the "else" expressiony 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 byIf 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 value1 forx>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 functionIf 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 ofIf functions. Usually, however, it is instead better to use functions likeWhich andSwitch.
This defines a function with three regions. UsingTrue as the third test makes this the default case:
This uses the first case in theWhich:
This uses the third case:
This defines a function that depends on the values of its argument modulo3:
Mod[7,3] is1, so this uses the second case in theSwitch:
17 matches neither0 nor1, but does match_:
An important point about symbolic systems such as the Wolfram Language is that the conditions you give may yield neitherTrue norFalse. Thus, for example, the conditionx==y does not yieldTrue orFalse unlessx andy have specific values, such as numerical ones.
In this case, the test gives neitherTrue norFalse, so both branches in theIf remain unevaluated:
You can add a special fourth argument toIf, which is used if the test does not yieldTrue orFalse:
If[test,then,else,unknown]
a form ofIf which includes the expression to use iftest is neitherTrue norFalse
TrueQ[expr]
giveTrue ifexpr isTrue, andFalse otherwise
lhs===rhs
or
SameQ[lhs,rhs]
giveTrue iflhs andrhs are identical, andFalse otherwise
lhs=!=rhs
or
UnsameQ[lhs,rhs]
giveTrue iflhs andrhs are not identical, andFalse otherwise
MatchQ[expr,form]
giveTrue if the patternform matchesexpr, and giveFalse otherwise
Functions for dealing with symbolic conditions.
The Wolfram Language leaves this as a symbolic equation:
Unlessexpr is manifestlyTrue,TrueQ[expr] effectively assumes thatexpr isFalse:
Unlike==,=== tests whether two expressions are manifestly identical. In this case, they are not:
The main difference betweenlhs===rhs andlhs==rhs is that=== always returnsTrue orFalse, 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 thestructure 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 astest1&&test2&&. An important point is that the result from this combination of tests will beFalse ifany of thetesti yieldFalse. The Wolfram Language always evaluates thetesti in turn, stopping if any of thetesti yieldFalse.
expr1&&expr2&&expr3
evaluate until one of theexpri is found to beFalse
expr1||expr2||expr3
evaluate until one of theexpri is found to beTrue
Evaluation of logical expressions.
This function involves a combination of two tests:
Here both tests are evaluated:
Here the first test yieldsFalse, so the second test is not tried. The second test would involve1/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}]
evaluateexpr repetitively, withi varying from1 toimax in steps of1
Do[expr,{i,imin,imax,di}]
evaluateexpr withi varying fromimin toimax in steps ofdi
Do[expr,{i,list}]
evaluateexpr withi taking on values fromlist
Do[expr,{n}]
evaluateexprn times
Simple looping constructs.
This evaluatesPrint[i^2], withi running from1 to4:
This executes an assignment fort in a loop withk running from2 to6 in steps of2:
The way iteration is specified inDo is exactly the same as in functions likeTable andSum. Just as in those functions, you can set up several nested loops by giving a sequence of iteration specifications toDo.
This loops over values ofi from1 to4, and for each value ofi, loops overj from1 toi-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 inDo just as you can inTable and other iteration functions.
This repeats the assignmentt=1/(1+t) three times:
You can put a procedure insideDo:
Nest[f,expr,n]
applyf toexprn times
FixedPoint[f,expr]
start withexpr, and applyf repeatedly until the result no longer changes
NestWhile[f,expr,test]
start withexpr, and applyf repeatedly until applyingtest to the result no longer yieldsTrue
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 nestsf three times:
By nesting a pure function, you can get the same result as in the example withDo 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 usingFixedPoint[f,x].
FixedPoint goes on applying a function until the result no longer changes:
You can useFixedPoint to imitate the evaluation process in the Wolfram Language, or the operation of functions such asexpr//.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 yieldsTrue.
Catch[expr]
evaluateexpr untilThrow[value] is encountered, then returnvalue
Catch[expr,form]
evaluateexpr untilThrow[value,tag] is encountered, whereform matchestag
Catch[expr,form,f]
returnf[value,tag] instead ofvalue
Nonlocal control of evaluation.
When theThrow is encountered, evaluation stops, and the current value ofi is returned as the value of the enclosingCatch:
Throw andCatch provide a flexible way to control the process of evaluation in the Wolfram Language. The basic idea is that whenever aThrow is encountered, the evaluation that is then being done is stopped, and the Wolfram Language immediately returns to the nearest appropriate enclosingCatch.
Scan applies the functionPrint to each successive element in the list, and in the end just returnsNull:
The evaluation ofScan stops as soon asThrow is encountered, and the enclosingCatch returns as its value the argument ofThrow:
The same result is obtained withMap, even thoughMap would have returned a list if its evaluation had not been stopped by encountering aThrow:
You can useThrow andCatch 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 usingThrow, 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 noThrow encountered, the result here is just as before:
Now the evaluation of theNestList is diverted, and the single number given as the argument ofThrow is returned:
Throw andCatch operate in a completely global way: it does not matter how or where aThrow is generatedit will always stop evaluation and return to the enclosingCatch.
TheThrow stops the evaluation off, and causes theCatch to return justa, with no trace off left:
This defines a function which generates aThrow when its argument is larger than 10:
NoThrow is generated here:
But here theThrow generated inside the evaluation ofg returns to the enclosingCatch:
In small programs, it is often adequate to useThrow[value] andCatch[expr] in their simplest forms. But particularly if you write larger programs that contain many separate pieces, it is usually much better to useThrow[value,tag] andCatch[expr,form]. By keeping the expressionstag andform local to a particular piece of your program, you can then ensure that yourThrow andCatch will also operate only within that piece.
Here theThrow is caught by the innerCatch:
But here it is caught only by the outerCatch:
You can use patterns in specifying the tags which a particularCatch should catch:
This keeps the taga completely local:
You should realize that there is no need for the tag that appears inThrow to be a constant; in general it can be any expression.
Here the innerCatch catches all throws with tags less than 4, and continues theDo. But as soon as the tag reaches 4, the outerCatch is needed:
When you useCatch[expr,form] withThrow[value,tag], the value returned byCatch is simply the expressionvalue given in theThrow. If you useCatch[expr,form,f], however, then the value returned byCatch is insteadf[value,tag].
Heref is applied to the value and tag in theThrow:
If there is noThrow,f is never used:
While[test,body]
evaluatebody repetitively, so long astest isTrue
For[start,test,incr,body]
evaluatestart, then repetitively evaluatebody andincr, untiltest fails
General loop constructs.
Functions likeDo,Nest, andFixedPoint provide structured ways to make loops in Wolfram Language programs, whileThrow andCatch 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 functionsWhile andFor, which perform operations repeatedly, stopping when a specified condition fails to be true.
TheWhile loop continues until the condition fails:
The functionsWhile andFor in the Wolfram Language are similar to the control structureswhile andfor 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 LanguageFor loops relative to C language ones.
This is a very common form for aFor loop.i++ increments the value ofi:
Here is a more complicatedFor loop. Notice that the loop terminates as soon as the testi^2<10 fails:
In the Wolfram Language, bothWhile andFor always evaluate the loop test before evaluating the body of the loop. As soon as the loop test fails to beTrue,While andFor terminate. The body of the loop is thus only evaluated in situations where the loop test isTrue.
The loop test fails immediately, so the body of the loop is never evaluated:
In aWhile orFor 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 andFor 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 useThrow andCatch. 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 valueexpr from a function
Goto[name]
go to the elementLabel[name] in the current procedure
Throw[value]
returnvalue as the value of the nearest enclosingCatch(nonlocal return)
Control flow functions.
TheBreak[] causes the loop to terminate as soon ast exceeds19:
Whenk<3, theContinue[] causes the loop to be continued, without executingt+=2:
Return[expr] allows you to exit a particular function, returning a value. You can think ofThrow 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 ofReturn. This particular procedure could equally well have been written without usingReturn:
When the argument is greater than 5, the firstReturn in the procedure is used:
This function "throws"error if its argument is negative:
NoThrow is generated here:
But in this case aThrow is generated, and the wholeCatch returns the valueerror:
Functions likeContinue[] andBreak[] 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 aLabel as an element in a procedure, you can useGoto to transfer control to this element.
This goes on looping untilq exceeds6:
Note that you can useGoto in a particular Wolfram Language procedure only when theLabel it specifies occurs as an element of the same Wolfram Language procedure. In general, use ofGoto 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 usingSow andReap.
Sow[val]
sow the valueval for the nearest enclosingReap
Reap[expr]
evaluateexpr, returning also a list of values sown bySow
UsingSow andReap.
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:
LikeThrow andCatch,Sow andReap can be used anywhere in a computation.
This defines a function that can do aSow:
This nests the function, reaping all cases below 1/2:
Sow[val,tag]
sowval with a tag to indicate when to reap
Sow[val,{tag1,tag2,}]
sowval for each of thetagi
Reap[expr,form]
reap all values whose tags matchform
Reap[expr,{form1,form2,}]
make separate lists for each of theformi
Reap[expr,{form1,},f]
applyf to each distinct tag and list of values
Sowing and reaping with tags.
This reaps only values sown with tag x:
Here1 is sown twice with tagx:
Values sown with different tags always appear in different sublists:
This makes a sublist for each form of tag being reaped:
This appliesf 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 ofexpr
Trace[expr,form]
include only expressions that match the patternform
Tracing the evaluation of expressions.
The expression1+1 is evaluated immediately to2:
The2^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 includesall the intermediate expressions involved in the evaluation ofexpr. Except in rather simple cases, however, the number of intermediate expressions generated in this way is typically very large, and the list returned byTrace is difficult to understand.
Trace[expr,form] allows you to "filter" the expressions thatTrace records, keeping only those that match the patternform.
Here is a recursive definition of a factorial function:
This givesall the intermediate expressions generated in the evaluation offac[3]. The result is quite complicated:
This shows only intermediate expressions of the formfac[n_]:
You can specify any pattern inTrace:
Trace[expr,form] effectively works by intercepting every expression that is about to be evaluated during the evaluation ofexpr, and picking out those that match the patternform.
If you want to trace "calls" to a function likefac, you can do so simply by tellingTrace to pick out expressions of the formfac[n_]. You can also use patterns likef[n_,2] to pick out calls with particular argument structure.
A typical Wolfram System program, however, consists not only of "function calls" likefac[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 inTrace to pick out any kind of Wolfram System program element. Thus, for example, you can use a pattern likek=_ to pick out all assignments to the symbolk.
This shows the sequence of assignments made fork:
Trace[expr,form] can pick out expressions that occur at any time in the evaluation ofexpr. The expressions need not, for example, appear directly in the form ofexpr that you give. They may instead occur, say, during the evaluation of functions that are called as part of the evaluation ofexpr.
Here is a function definition:
You can look for expressions generated during the evaluation ofh:
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 functionf
Trace[expr,i=_]
show assignments toi
Trace[expr,_=_]
show all assignments
Trace[expr,Message[___]]
show messages generated
Some ways to useTrace.
The functionTrace 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 byTrace has a nested structure, which represents the "structure" of the computation.
The basic idea is that each sublist in the list returned byTrace 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 byTrace.
Here is a sequence of assignments:
This yields an evaluation chain reflecting the sequence of transformations fora[i] used:
The successive forms generated in the simplification ofy+x+y show up as successive elements in its evaluation chain:
Each argument of the functionf 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 byTrace.
The subsidiary evaluations here come from evaluation of the arguments off andg:
Here is a function with a condition attached:
The evaluation offe[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 definitionfac[n_]:=n fac[n-1], the evaluation offac[6] yields the expression6 fac[5], which containsfac[5] as a subexpression.
The successive instances offac generated appear in successively nested sublists:
With this definition,fp[n-1] is obtained directly as the value offp[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 offib[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 useTrace[expr,f] to see all the steps in the evaluation ofexpr that are performed using transformation rules associated with the symbolf. 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 ofexpr whereform matcheseither 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 symbolf
Trace[expr,f|g]
show all evaluations associated with eitherf org
Tracing evaluations associated with particular tags.
This shows only intermediate expressions that matchfac[_]:
This shows all evaluations that use transformation rules associated with the symbolfac:
Here is a rule for thelog function:
This traces the evaluation oflog[abcd], showing all transformations associated withlog:
Trace[expr,form,TraceOn->oform]
switch on tracing only within forms matchingoform
Trace[expr,form,TraceOff->oform]
switch off tracing within any form matchingoform
Switching off tracing inside certain forms.
Trace[expr,form] allows you to trace expressions matchingform generated at any point in the evaluation ofexpr. Sometimes, you may want to trace only expressions generated during certain parts of the evaluation ofexpr.
By setting the optionTraceOn->oform, you can specify that tracing should be done only during the evaluation of forms that matchoform. Similarly, by settingTraceOff->oform, you can specify that tracing should be switched off during the evaluation of forms that matchoform.
This shows all steps in the evaluation:
This shows only those steps that occur during the evaluation offac:
This shows only those steps that do not occur during the evaluation offac:
Trace[expr,lhs->rhs]
find all expressions matchinglhs that arise during the evaluation ofexpr, and replace them withrhs
Applying rules to expressions encountered during evaluation.
This tellsTrace to return only the arguments offib used in the evaluation offib[5]:
A powerful aspect of the Wolfram SystemTrace 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 thatTrace wraps all expressions that appear in the list it produces withHoldForm to prevent them from being evaluated. TheHoldForm 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 withHoldForm 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 byTrace, and which are expressions being evaluated:
Looking at the input form resolves any ambiguities:
When you use a transformation rule inTrace, the result is evaluated before being wrapped withHoldForm:
For sophisticated computations, the list structures returned byTrace can be quite complicated. When you useTrace[expr,form],Trace will include as elements in the lists only those expressions that match the patternform. But whatever pattern you give, the nesting structure of the lists remains the same.
This shows all occurrences offib[_] in the evaluation offib[3]:
This shows only occurrences offib[1], but the nesting of the lists is the same as forfib[_]:
You can set the optionTraceDepth->n to tellTrace to include only lists nested at mostn levels deep. In this way, you can often pick out the "big steps" in a computation, without seeing the details. Note that by settingTraceDepth orTraceOff you can avoid looking at many of the steps in a computation, and thereby significantly speed up the operation ofTrace 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 ofexpr, ignoring steps that lead to lists nested more thann levels deep
Restricting the depth of tracing.
When you useTrace[expr,form], you get a list of all the expressions that matchform produced during the evaluation ofexpr. 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 optionTraceForward->True inTrace.
This shows not only expressions that matchfac[_], but also the results of evaluating those expressions:
Expressions picked out usingTrace[expr,form] typically lie in the middle of an evaluation chain. By settingTraceForward->True, you tellTrace to include also the expression obtained at the end of the evaluation chain. If you setTraceForward->All,Trace will includeall the expressions that occur after the expression matchingform on the evaluation chain.
WithTraceForward->All, all elements on the evaluation chain after the one that matchesfac[_] are included:
By setting the optionTraceForward, 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 optionTraceBackward. WhatTraceBackward does is to show you whatpreceded a particular form of expression on an evaluation chain.
This shows that the number120 came from the evaluation offac[5] during the evaluation offac[10]:
Here is the whole evaluation chain associated with the generation of the number120:
TraceForward andTraceBackward 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 usingTraceAbove. If you set the optionTraceAbove->True, thenTrace will include the initial and final expressions in all the relevant evaluation chains. WithTraceAbove->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 contains120:
This shows all the ways thatfib[2] is generated during the evaluation offib[5]:
Trace[expr,form,opts]
trace the evaluation ofexpr using the specified options
TraceForward->True
include the final expression in the evaluation chain containingform
TraceForward->All
include all expressions followingform in the evaluation chain
TraceBackward->True
include the first expression in the evaluation chain containingform
TraceBackward->All
include all expressions precedingform in the evaluation chain
TraceAbove->True
include the first and last expressions in all evaluation chains that contain the chain containingform
TraceAbove->All
include all expressions in all evaluation chains that contain the chain containingform
Option settings for including extra steps in trace lists.
The basic way thatTrace[expr,] works is to intercept each expression encountered during the evaluation ofexpr, and then to use various criteria to determine whether this expression should be recorded. Normally, however,Trace intercepts expressions onlyafter function arguments have been evaluated. By settingTraceOriginal->True, you can getTrace also to look at expressionsbefore function arguments have been evaluated.
This includes expressions that matchfac[_] both before and after argument evaluation:
The list structure produced byTrace 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 setTraceOriginal->True, thenTrace 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 followingform in the evaluation chain
TraceBackwardFalse
whether to show expressions precedingform in the evaluation chain
TraceAboveFalse
whether to show evaluation chains leading to the evaluation chain containingform
TraceOriginalFalse
whether to look at expressions before their heads and arguments are evaluated
Additional options forTrace.
When you useTrace 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 asModule create symbols with new names to represent local variables. Thus, even if you called a variablex in the original code for your program, the variable may effectively be renamedx$nnn when the program is executed.
Trace[expr,form] is set up so that by default a symbolx that appears inform will match all symbols with names of the formx$nnn that arise in the execution ofexpr. As a result, you can for example useTrace[expr,x=_] to trace assignment to all variables, local and global, that were namedx in your original program.
Trace[expr,form,MatchLocalNames->False]
include all steps in the execution ofexpr that matchform, 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 variablex, and not any local variables that were originally namedx. You can do this by setting the optionMatchLocalNames->False.
This traces assignments to all variables with names of the formx$nnn:
This traces assignments only to the specific global variablex:
The functionTrace 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 functionTracePrint works essentially likeTrace, 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 offib[3]:
The sequence of expressions printed byTracePrint corresponds to the sequence of expressions given in the list structure returned byTrace. Indentation in the output fromTracePrint corresponds to nesting in the list structure fromTrace. You can use theTrace optionsTraceOn,TraceOff andTraceForward inTracePrint. However, sinceTracePrint produces output as it goes, it cannot support the optionTraceBackward. In addition,TracePrint is set up so thatTraceOriginal is effectively always set toTrue.
Trace[expr,]
trace the evaluation ofexpr, returning a list structure containing the expressions encountered
TracePrint[expr,]
trace the evaluation ofexpr, printing the expressions encountered
TraceDialog[expr,]
trace the evaluation ofexpr, initiating a dialog when each specified expression is encountered
TraceScan[f,expr,]
trace the evaluation ofexpr, applyingf toHoldForm of each expression encountered
Functions for tracing evaluation.
This enters a dialog whenfac[5] is encountered during the evaluation offac[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 offac[10]:
The functionTraceDialog 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.
WhatTraceDialog does is to call the functionDialog on a sequence of expressions. TheDialog function is discussed in detail in"Dialogs". When you callDialog, 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,] appliesf to each expression that arises. The expression is wrapped withHoldForm to prevent it from evaluating.
InTraceScan[f,expr,], the functionf is applied to expressions before they are evaluated.TraceScan[f,expr,patt,fp] appliesf before evaluation, andfp after evaluation.
The Evaluation Stack
Throughout any computation, the Wolfram System maintains anevaluation stack containing the expressions it is currently evaluating. You can use the functionStack to look at the stack. This means, for example, that if you interrupt the Wolfram System in the middle of a computation, you can useStack 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 whenx is being evaluated, the stack associated with the evaluation of an expression likef[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 thePrint 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 byTrace with the optionTraceAbove set toTrue.
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 matchform
Looking at the evaluation stack.
It is rather rare to callStack directly in your main Wolfram System session. More often, you will want to callStack 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 evaluatesfac[10], starting a dialog when it encountersfac[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 recordall expressions currently being evaluated. Under some circumstances, however, this may be inconvenient. For example, executingPrint[Stack[]] will always show a stack withPrint as the last function.
The functionStackInhibit allows you to avoid this kind of problem.StackInhibit[expr] evaluatesexpr without modifying the stack.
StackInhibit preventsPrint from being included on the stack:
Functions likeTraceDialog automatically callStackInhibit each time they start a dialog. This means thatStack does not show functions that are called within the dialog, only those outside.
StackInhibit[expr]
evaluateexpr without modifying the stack
StackBegin[expr]
evaluateexpr with a fresh stack
StackComplete[expr]
evaluateexpr with intermediate expressions in evaluation chains included on the stack
Controlling the evaluation stack.
By usingStackInhibit andStackBegin, you can control which parts of the evaluation process are recorded on the stack.StackBegin[expr] evaluatesexpr, starting a fresh stack. This means that during the evaluation ofexpr, the stack does not include anything outside theStackBegin. Functions likeTraceDialog[expr,] callStackBegin before they begin evaluatingexpr, so that the stack shows howexpr is evaluated, but not howTraceDialog was called.
StackBegin[expr] uses a fresh stack in the evaluation ofexpr:
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 usingStackComplete.
WhatStackComplete[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 fromTrace with the optionTraceBackward->All as well asTraceAbove->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 likex=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:
$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 byTrace.$IterationLimit limits the maximum length of any particular evaluation chain, or the maximum length of any single list in the structure produced byTrace.
$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 toInfinity. Note that on most computer systems, you should never set$RecursionLimit=Infinity, as discussed in"Memory Management".
This resets$RecursionLimit and$IterationLimit to40:
Now infinite definitions like this are stopped after just 40 steps:
The variablei was incremented to 37 rather than 40 asCompoundExpression,t andPlus are also in the evaluation chain:
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:
Restore the two global limits to their default values:
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 likex=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 typeUpdate[s] to tell the Wolfram Language to update all expressions involvings.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, executingInterrupt[] 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]
evaluateexpr and return the result, orfailexpr if an abort occurs
AbortProtect[expr]
evaluateexpr, masking the effect of aborts until the evaluation is complete
Interrupts and aborts.
The functionAbort[] has the same effect as interrupting a computation, and selecting theabort option in the interrupt menu.
You can useAbort[] to implement an "emergency stop" in a program. In almost all cases, however, you should try to use functions likeReturn andThrow, which lead to more controlled behavior.
Abort terminates the computation, so only the firstPrint 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 functionCheckAbort. If an abort occurs during the evaluation ofexpr inCheckAbort[expr,failexpr], thenCheckAbort returnsfailexpr, but the abort propagates no further. Functions likeDialog useCheckAbort in this way to contain the effect of aborts.
CheckAbort catches the abort, printsc and returns the valueaborted:
The effect of theAbort is contained byCheckAbort, sob 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 callingAbort. The functionAbortProtect allows you to evaluate an expression, saving up any aborts until after the evaluation of the expression is complete.
TheAbort is saved up untilAbortProtect is finished:
TheCheckAbort sees the abort, but does not propagate it further:
Even insideAbortProtect,CheckAbort will see any aborts that occur, and will return the appropriatefailexpr. Unless thisfailexpr itself containsAbort[], the aborts will be "absorbed" by theCheckAbort.
Compiling Wolfram Language Expressions
If you make a definition likef[x_]:=xSin[x], the Wolfram Language will store the expressionxSin[x] in a form that can be evaluated for anyx. Then when you give a particular value forx, the Wolfram Language substitutes this value intoxSin[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 forx 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 couldassume thatx will be a machine number, then it could avoid many steps, and potentially evaluate an expression likexSin[x] much more quickly.
UsingCompile, you can constructcompiled 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 expressionexpr and returns a "compiled function" which evaluates this expression when given arguments.
In general,Compile creates aCompiledFunction 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 evaluatesexpr for numerical values of thexi
Creating compiled functions.
This definesf to be a pure function which evaluatesxSin[x] for anyx:
This creates a compiled function for evaluatingxSin[x]:
f andfc yield the same results, butfc 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 callCompile, you can get a compiled function which can be executed more quickly than an ordinary Wolfram Language function.
For simple expressions such asxSin[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 asBesselK orEigenvalues, 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 argument0.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 useCompile. Thus, for example,NIntegrate by default automatically usesCompile on the expression you tell it to integrate. Similarly, functions likePlot andPlot3D useCompile on the expressions you ask them to plot. Builtin functions that useCompile typically have the optionCompiled. SettingCompiled->False tells the functions not to useCompile.
Compile[{{x1,t1},{x2,t2},},expr]
compileexpr assuming thatxi is of typeti
Compile[{{x1,t1,n1},{x2,t2,n2},},expr]
compileexpr assuming thatxi is a rankni array of objects each of typeti
Compile[vars,expr,{{p1,pt1},}]
compileexpr, assuming that subexpressions which matchpi are of typepti
_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 orFalse), 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 useTrue|False to specify a logical variable that must be eitherTrue orFalse.
This compiles the expression5i+j with the assumption thati andj 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 thatCompile 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 compilesx^com[i] using the assumption thatcom[_] is always an integer:
This evaluates the compiled function:
The idea ofCompile 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 byCompile 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 actualvalues of the arguments you specify. Thus, for example,Sqrt[x] yields a real number result for realx ifx is not negative, but yields a complex number ifx 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 byCompile 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 ofCompile 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:

Related Guides

Top

[8]ページ先頭

©2009-2025 Movatter.jp