Mathematica Expressions

What Is An Expression?

In Mathematica, everything is an expression. The command FullForm  shows the internal structure of all Mathematica expressions.

FullForm[{1,2,3}]

Every expression has a "Head", which refers to the type of the expression.

Head[{1,2,3}]

Head[a==b]

Head[x->1]

Head[100]

Head[100.2]

Head[(100/3)]

Head[a]

Head["100a"]

Even Mathematica commands are represented as expressions, e.g.

FullForm[Hold[Solve[(x^2)-3==4,x]]]

only that many commands have some "nice syntax" that hides the internal form of the expression, e.g.

FullForm[Hold[(x^2)/.x->a]]

We already see here: For commands we need to prevent Mathematica from immediately executing the command before it can show its internal form by wrapping the command into Hold. Otherwise, we would only see the internal form only of the result!

FullForm[(x^2)/.x->a]

We will see more details in the subsequent sections.

Evaluation of Expressions

The driving engine of Mathematica is the evaluation of expressions. This is, actually, what happens when you type ⇧+↵ in a Mathematica input cell: The expression in the current input cell is sent to the kernel for evaluation.
"Evaluation" means rewriting the expression w.r.t. user–defined oder built–in definitions.

(3*5+Sin[π])f[3+5,x]

Hold[(3*5+Sin[π])f[3+5,x]]//FullForm

There are built–in definitions for Times and Sin that rewrite 3*5 to 15 and Sin[π] to 0, then there is a built–in definition for Plus that rewrites 15+0 to 15. Similarly, 3+5 rewrites to 8. Since there is no definiton for f[8,x], the final result is 15f[8,x].

(3*5+Sin[π])f[3+5,x]//Trace

As we see in the example above, Mathematica first evaluates the subexpressions and then evaluates the resulting expression. Of course, in each subexpression this process is continued recursively. The process stops when there is no definition anymore that can be applied to the expression. In the example, evaluating the first subexpression stopped at 15,  the second subexpression f[3+5,x] evaluated to f[8,x], which did not change further, because there is neither a definition for x nor a definition for f[8,x], thus resulting in the expression 15*f[8,x]. Since there is no definition for Times that can be used for rewriting 15*f[8,x] the evaluation stops and the result of this evaluation is 15*f[8,x]. 
We can, however, give definitions for x and/or f.

x=2;

(3*5+Sin[π])f[3+5,x]

f[8,2]=3;

(3*5+Sin[π])f[3+5,x]

Both commands and data are just Mathematica expressions! Expressions, for which there is a definition, behave like commands. Expressions, for which there is no definition, behave like data.
Commands:

Sin[π]

f[8,2]

Data:

List[1,2]//FullForm

f[1,2]

Attributes

Attributes may influence the evaluation of expressions.

Attributes[f]

In this setup, Mathematica performs "call by value" in function calls.

SetAttributes[f,HoldFirst]

Use ?f for inspecting the user–definitions available for f.

?f

Trace[f[3+5,x]]

f[3+5,x]

ClearAttributes[f,HoldFirst]

SetAttributes[f,HoldRest]

?f

Trace[f[3+5,x]]

SetAttributes[f,HoldFirst]

?f

ClearAttributes[f,HoldRest]

?f

Trace[f[3+5,x]]

f[3+5,x]

SetAttributes[f,Listable]

?f

Trace[f[{a,3},3+1]]

Orderless brings arguments into an internal default–order before it evaluates the expression.

SetAttributes[f,Orderless]

?f

f[8,2]

f[x,2]

Flat flattens nested expressions.

SetAttributes[f,Flat]

f[8,f[2,6]]

Further attributes can be found in the manual.

Explicit Evaluation or Non–Evaluation Depsite of Attributes

ClearAll clears the definitions and all attributes as well.

ClearAll[f]

The first possibility to keep a parameter unevaluated is to wrap it into Unevaluated.

f[x_Plus]:="The sum expression is: "<>ToString[x]

f[x_]:="The parameter is: "<>ToString[x]

f[x+y]

f[x+3]

f[Unevaluated[5+3]]

Attributes[ToString]

What we see is that Unevaluated keeps the parameter unevaluated in the call to f, but in further evaluations the passed parameter is evaluated. The stronger form is Hold.

f[Hold[5+3]]

g[Hold[3+5],Hold[3+98]]

ReleaseHold[%]

Hold effectively forms a new expression and all parts inside Hold are kept unevaluated.
Evaluate can be used to evaluate parameters in the presence of Hold–Attributes.

ClearAll[f]

SetAttributes[f,HoldFirst]

f[x_Plus]:="The sum expression is: "<>ToString[Unevaluated[x]]

f[x_]:="The parameter is: "<>ToString[x]

f[3+5]

f[Evaluate[3+5]]

SetAttributes[ToString,HoldFirst]

??ToString

??Plot

Note also, that Hold–Attributes don't prevent the parameter from being evaluated when processed further.

f[3*5]

With HoldAllComplete not even Evaluate has an effect.

ClearAll[f]

Attributes[f]={HoldAllComplete};

f[x_]:=HoldForm[x+1]

f[Evaluate[3+5]]

FullForm[%]

We see that HoldForm is similar to Hold in that it keeps its parameters unevaluated. HoldForm, however disappears in the display of the expression.

HoldForm[3+5]

Hold[3+5]

ClearAll[f]

f[x_]:=If[x>2,x-2,((x+1)/2),x]

f[3+5]

f[3-5]

a=f[Hold[3+5]]

Note, that Hold and HoldForm can be removed inside expressions using ReleaseHold:

ReleaseHold[a==8]

ReleaseHold[HoldForm[3+5]]

ClearAll[f]

Execution of Mathematica–Programs

The execution of Mathematica–programs is driven exclusively by the mechanism of evaluation of expressions as described above in combination with "pattern matching". We define a "program" P by giving a definition in the form

lhs:=rhs

where, in general, lhs is a pattern and rhs is an arbitrary expression. A program call to P happens, if, during the evaluation of some expression, there appears an expression that "matches" lhs (with a certain substitution of pattern components), then the same substitution is carried out on rhs and the resulting expression is evaluated. rhs may eventually contain expressions such as Module[...], If[...], Switch[...], etc. However, the execution of these "programming constructs" also just follows the scheme of expression evaluation, only that most of these "programming constructs" use a special treatment of their parameters, since the parameters mostly contain entire program fragments.

Attributes[Module]

Attributes[If]

Hence, "programming constructs" are just expressions, whose evaluation simulates a certain "program flow". The behavior of a Mathematica–program is completely determined by the mechanism of evaluation.

The Difference between = and :=

We have seen two different ways of assignment up to now: = and :=. In most cases, = is used for simple assignment of values, whereas := is used in program definitions. However, this is not a law! The difference between the two is quite simple.

FullForm[HoldForm[lhs=rhs]]

FullForm[HoldForm[lhs:=rhs]]

Attributes[{Set,SetDelayed}]

This is all about the difference between the two: due to the attribute HoldFirst, = evaluates the right–hand side of the expression before the assignment is made, whereas := assigns the unevaluated form of the right–hand side. Thus, the only difference is, that in lhs=rhs the expression rhs is evaluated at the time when the assignment is made, whereas in lhs:=rhs the evaluation of rhs is delayed to the time when lhs is accessed.
In cases, where the right–hand side does not evaluate in the first place, there is in fact no difference!

ClearAll[f,a,x]

a=8;

?a

a

a:=8

?a

a

f[x_,y_]:=x+y

?f

f[3,5]

f[x_,y_]=x+y;

?f

f[3,5]

However, when defining a program, the intention usually is that the program is executed when it is called, not when it is defined, therefore a program definition commonly uses := .

f[a_,y_]=a+y;

?f

Clear[f]

BUT: Assume we have the function f given as

f[x_]:=(E^(x-3))Sin[2x]

We want to define a function, say F, such that F[z]:=(∫_0^z)f[x]dx.

F[z_]:=Integrate[f[x],{x,0,z}]

?F

F[3]//Timing

F[z_]=Integrate[f[x],{x,0,z}];

?F

F[3]//Timing

The Details of Evaluation

When evaluating an expression h[(Subscript[x, 1]),…,(Subscript[x, n])] Mathematica

first evaluates the head h,

then evaluates the arguments (Subscript[x, 1]),…,(Subscript[x, n]) depending on the attributes of f,

then applies transformations related to attributes such as Orderless, Flat, and Listable,

then applies user–definitions,

then applies built–in definitions, and

finally evaluates the resulting expression.

When a definition is evaluated, as discussed before, the left–hand side is kept unevaluated. However, in a definition

f[(Subscript[x, 1]),…,(Subscript[x, n])]:=rhs

the arguments (Subscript[x, 1]),…,(Subscript[x, n]) will be evaluated corresponding to the attributes of f and possibly the arguments will be transformed according to attributes of f such as Orderless, Flat, and Listable in order to have definitions coherent with the evaluation strategy applied when later applying the definitions. 
Thus, in general, attributes should be specified before the function definitions are given!
We go back to the example that we already had before:

ClearAll[f]

f[8,2]=3;

SetAttributes[f,Orderless]

f[8,2]

?f

Clear[f]

f[8,2]=3;

?f

f[8,2]

Thus, Orderless is useful for a commutative operation, Flat is useful for an associative operation, and Listable is useful for operations to be applied component–wise.

Currying

Currying means that the head of an expression can itself be a composed expression, it need not necessarily be just a symbol.

ClearAll[f]

f[op_String,x_,y_]:=Switch[op,
"Plus",Plus,
"Times",Times,
_,Hold][x,y]

f["Plus",3,5]

f["Times",3,5]

f["Minus",3,5]

Arrays and Lists

Clear[a,b,c,f]

Arrays and lists in Mathematica are the same.

{a,b,c}

Range[2,10]

Range[10]

Range[1,10,2]

Table[(i^2),{i,2,10}]

Table[(i^2),{i,10}]

Table[(i^2),{i,1,10,2}]

Table[i/j,{i,10},{j,5,10}]

Array[f,{10}]

FullForm[{a,b,c}]

Lists are again only expressions! There are (almost) no operations particularly for lists. Rather, there are operations for expressions (accessing parts, manipulating the structure, etc.), which can be used, as special cases, also for lists, see the subsequent sections.

List Assignment

Assignment to symbols in a list can be done simultaneously, i.e.

{a,b,c,d}=Table[Random[],{4}]

a

{a,b,c,d}={c,d,a,b}

a

b

Clear[a,b,c,d]

Manipulating Expressions

Clear[a,b,c,d,e,f]

Accessing Parts of Expressions

We can access the subexpressions by their position using Part.

Part[{a,b,c},3]

Part[a==b,1]

Part[a==b,2]

Part[f[a,b,c,d,e],2]

As an abbreviation, we may use the (postfix) operator "[[  ]]" (enter via Esc[[Esc and Esc]]Esc, respectively) or in its long form "[[" and  "]]").

{a,b,c}[[3]]

(a==b)[[2]]

Negative positions are counted backwards from the last position of the expression.

{a,b,c}[[-1]]

Expressions may be nested, i.e. at every position in an expression there may be again an expression. Atomic expressions in this recursive structure are symbols, numbers, and strings.

expr=f[a,g[23],h[1/2,p["K[x]"]]]

We can use multi–indices to access parts in nested expressions.

expr[[2,1]]

expr[[3,2]]

expr[[3,2,1]]

Furthermore, we can access several parts simultaneously. Note that the head of the original expression is put as the head of the resulting expression!

expr[[{1,2}]]

Accessing parts of expressions can be tricky if Hold–attributes maintain subexpressions in unevaluated form.

ClearAll[f]

SetAttributes[f,HoldAll]

expr=f[2+2,2+3]

Suppose you want to further process the unevaluated subexpression contained in this expression.

Part[expr,1]

expr[[1]]

expr[[2]]

As a workaround, one can use simultaneous access, which puts the original head as the head of the expression and, therefore, brings the Hold–attributes into play.

expr[[{2}]]

As an alternative to Part there is Extract, which uses a slightly different syntax for specifying the position

Extract[expr,{1}]

Extract[expr,{2}]

Extract[expr,{{2},{1}}]

As we see, the simultaneously extracted parts are always returned as a list, regardless of what the head of the original expression was (unlike Part). Specifying a third argument, we can force an arbitrary head to be applied to the extracted expressions.

Extract[expr,{2},Hold]

Extract[expr,{{2},{1}},Hold]

Extract[expr,{1},f]

Accessing Consecutive Parts of Expressions

Of course, selecting chunks of expressions—such as e.g. the first 10 parts or part 6 through 10—could be done by simultaneous access.

expr=Table[(i^2),{i,1,20}]

Part[expr,Table[i,{i,10}]]

Part[expr,Table[i,{i,6,10}]]

However, it is more convenient to use Take for this purpose.

Take[expr,10]

Take[expr,{6,10}]

Take[expr,{6,10,2}]

Of course …

Take[expr,-3]

Take[expr,{-5,-3}]

Take[expr,{-5,-3,2}]

Accessing Parts via Non–Integer Indices (Associative Arrays)

ClearAll[f]

A datastructure that allows to access parts via non–integer indices is often called associative array. In Mathematica, we would use standard expressions for representing associative arrays. Think of some object, say f, whose parts (values) you want to access through "indices" named "winter", "spring", "summer", and "autumn". We would define the individual values as

f["winter"]=3;
f["spring"]=5;
f["summer"]="some value";
f["autumn"]={a,b,c};

By just the normal way of expression evaluation, we can access the values by

f["spring"]

f["autumn"]

?f

It should be clear, that any expression can serve as the index, we are not restricted to strings!

Accessing Parts by Pattern Matching

expr=f[a,g[23],h[1/2,p["K[x]",10]]]

Cases[expr,_g]

Cases[expr,_Integer]

By default, Cases only searches on the first level of a nested expression. The next call will search up to level 2.

Cases[expr,_Integer,2]

Cases[expr,_Integer,Infinity]

To search at level 3 only, use

Cases[expr,_Integer,{3}]

Cases[expr,_String]

Cases[expr,_String,3]

Cases[expr,_Symbol]

Cases[expr,_Symbol,Infinity]

Cases[expr,_Symbol,Infinity,Heads->True]

We can even immediately transform the extracted parts.

Cases[expr,a_Integer?EvenQ->a/2,3]

Deleting Parts of Expressions

expr=f[a,g[23],h[1/2,p["K[x]",10]]]

Delete[expr,3]

Delete[expr,{3,2}]

Delete[expr,{{1},{3}}]

Deleting Consecutive Parts of Expressions

Of course, deleting chunks of expressions—such as e.g. the first 10 parts or part 6 through 10—could be done by simultaneous deletion.

expr=Table[(i^2),{i,1,20}]

Delete[expr,Table[{i},{i,10}]]

Delete[expr,Table[{i},{i,6,10}]]

However, it is more convenient to use Drop for this purpose.

Drop[expr,10]

Drop[expr,{6,10}]

Drop[expr,{6,10,2}]

Of course …

Drop[expr,-3]

Drop[expr,{-5,-3}]

Drop[expr,{-5,-3,2}]

Deleting Parts by Pattern Matching

expr=f[a,g[23],h[1/2,p["K[x]",10]]]

DeleteCases[expr,_g]

DeleteCases[expr,_Integer]

For DeleteCases there are the same specialities like we saw them for Cases.

DeleteCases[expr,_Integer,2]

DeleteCases[expr,_Integer,Infinity]

To delete at level 3 only, use

DeleteCases[expr,_Integer,{3}]

DeleteCases[expr,_String]

DeleteCases[expr,_String,3]

DeleteCases[expr,_Symbol]

DeleteCases[expr,_Symbol,{2,Infinity},Heads->True]

DeleteCases[expr,_Symbol,Infinity,Heads->True]

Determining the Position of Elements in an Expression

expr=f[a,g[23],h[1/2,p["K[x]",10]]]

Position[expr,a]

Position[expr,_Integer]

The structure returned by Position specifying the position of elements in an expression corresponds exactly to the structure required for specifying positions in paramaters to Extract and Delete. Note, however, the position specification is slightly different in Part.

Structural Manipulation of Expressions

expr=Union[{b},{c,a}]

Append[expr,23]

expr

AppendTo[expr,d]

expr

expr=Join[{expr},Prepend[{{1/2,{"K[x]",{10}}}},{23}]]

Flatten[expr]

Flatten[expr,1]

Flatten[expr,2]

Flatten[expr,3]

Flatten is designed to be used on lists, primarily. Flatten, in fact, removes "List" when it appears as the head of a subexpression. To remove heads different from "List", we must specify the head symbol as third parameter to Flatten.

Flatten[{{a,b,c},g[23],p[1/2,"K[x]"]},1,g]

Flatten[{{a,b,c},g[23],p[1/2,"K[x]"]},1,p]

FlattenAt can be used to specify the position where the list should be flattened.

expr

FlattenAt[expr,3]

FlattenAt[expr,{3,2}]

FlattenAt[expr,{{1},{3,2}}]

Structuring an expression into parts of equal length can be done using Partition.

Partition[Table[i,{i,10}],2]

Partition[Table[i,{i,10}],3]

Partition[f[a,b,c,d,e],2]

We now just show some further structural manipulations available in Mathematica.

Reverse[expr]

Transpose[{{a,b},{c,d}}]

Of course, Transpose is meant to compute the transposed matrix of a given matrix, but it is in some situations useful to see Transpose as just a structural operation on nested list that "collects all i–th elements" of a nested list!

Dot[{a,b,c},{1,2,3}]

Inner[f,{a,b,c},{1,2,3}]

Inner[f,{a,b,c},{1,2,3},g]

Outer[f,{a,b,c},{1,2,3}]

Outer[List,{a,b,c},{1,2,3}]

Equal[{a,b,c},{1,2,3}]

Thread[Equal[{a,b,c},{1,2,3}]]

We urge to browse through the Mathematica Help (Section "Lists and Matrices") in order to find out even more possibilities available in Mathematica, and also to find out special capabilities of the functions mentioned in this chapter.