Expressions
Everything Is an Expression | Manipulating Expressions like Lists |
The Meaning of Expressions | Expressions as Trees |
Special Ways to Input Expressions | Levels in Expressions |
Parts of Expressions |
The Wolfram Language handles many different kinds of things: mathematical formulas, lists, and graphics, to name a few. Although they often look very different, the Wolfram Language represents all of these things in one uniform way. They are all expressions.
A prototypical example of a Wolfram Language expression is f[x,y]. You might use f[x,y] to represent a mathematical function . The function is named f, and it has two arguments, x and y.
You do not always have to write expressions in the form f[x,y,…]. For example, x+y is also an expression. When you type in x+y, the Wolfram Language converts it to the standard form Plus[x,y]. Then, when it prints it out again, it gives it as x+y.
You can see the full form of any expression by using FullForm[expr].
The object f in an expression f[x,y,…] is known as the head of the expression. You can extract it using Head[expr]. Particularly when you write programs in the Wolfram Language, you will often want to test the head of an expression to find out what kind of thing the expression is.
Here Head gives the name of the "operator":
Head[expr] | give the head of an expression: the f in f[x,y] |
FullForm[expr] | display an expression in the full form used by the Wolfram Language |
The notion of expressions is a crucial unifying principle in the Wolfram System. It is the fact that every object in the Wolfram System has the same underlying structure that makes it possible for the Wolfram System to cover so many areas with a comparatively small number of basic operations.
Although all expressions have the same basic structure, there are many different ways that expressions can be used. Here are a few of the interpretations you can give to the parts of an expression.
meaning of f | meaning of x,y,… | examples |
arguments or parameters | Sin[x]
,
f[x,y] | |
Command | arguments or parameters | Expand[(x+1)^2] |
Operator | operands | x+y
,
a=b |
elements | {a,b,c} | |
Object type | contents | RGBColor[r,g,b] |
Expressions in the Wolfram System are often used to specify operations. So, for example, typing in 2+3 causes 2 and 3 to be added together, while Factor[x^6-1] performs factorization.
Perhaps an even more important use of expressions in the Wolfram System, however, is to maintain a structure, which can then be acted on by other functions. An expression like {a,b,c} does not specify an operation. It merely maintains a list structure, which contains a collection of three elements. Other functions, such as Reverse or Dot, can act on this structure.
The full form of the expression {a,b,c} is List[a,b,c]. The head List performs no operations. Instead, its purpose is to serve as a "tag" to specify the "type" of the structure.
You can use expressions in the Wolfram System to create your own structures. For example, you might want to represent points in three‐dimensional space, specified by three coordinates. You could give each point as point[x,y,z]. The "function" point again performs no operation. It serves merely to collect the three coordinates together, and to label the resulting object as a point.
You can think of expressions like point[x,y,z] as being "packets of data", tagged with a particular head. Even though all expressions have the same basic structure, you can distinguish different "types" of expressions by giving them different heads. You can then set up transformation rules and programs which treat different types of expressions in different ways.
The Wolfram Language allows you to use special notation for many common operators. For example, although internally the Wolfram System represents a sum of two terms as Plus[x,y], you can enter this expression in the much more convenient form x+y.
The Wolfram Language has a definite grammar that specifies how your input should be converted to internal form. One aspect of the grammar is that it specifies how pieces of your input should be grouped. For example, if you enter an expression such as a+b^c, the Wolfram Language grammar specifies that this should be considered, following standard mathematical notation, as a+(b^c) rather than (a+b)^c. The Wolfram Language chooses this grouping because it treats the operator ^ as having a higher precedence than +. In general, the arguments of operators with higher precedence are grouped before those of operators with lower precedence.
You should realize that absolutely every special input form in the Wolfram Language is assigned a definite precedence. This includes not only the traditional mathematical operators, but also forms such as ->, := or the semicolons used to separate expressions in a Wolfram Language program.
The table in "Operator Input Forms" gives all the operators of the Wolfram Language in order of decreasing precedence. The precedence is arranged, where possible, to follow standard mathematical usage, and to minimize the number of parentheses that are usually needed.
You will find, for example, that relational operators such as < have lower precedence than arithmetic operators such as +. This means that you can write expressions such as x+y>7 without using parentheses.
There are nevertheless many cases where you do have to use parentheses. For example, since ; has a lower precedence than =, you need to use parentheses to write x=(a;b). The Wolfram System interprets the expression x=a;b as (x=a);b. In general, it can never hurt to include extra parentheses, but it can cause a great deal of trouble if you leave parentheses out, and the Wolfram System interprets your input in a way you do not expect.
f[x,y] | standard form for f[x,y] |
f@x | prefix form for f[x] |
x//f | postfix form for f[x] |
x~f~y | infix form for f[x,y] |
There are several common types of operators in the Wolfram Language. The + in x+y is an "infix" operator. The - in -p is a "prefix" operator. Even when you enter an expression such as f[x,y,…] the Wolfram Language allows you to do it in ways that mimic infix, prefix and postfix forms.
You will often want to add functions like N as "afterthoughts", and give them in postfix form:
You should notice that // has very low precedence. If you put //f at the end of any expression containing arithmetic or logical operators, the f is applied to the whole expression. So, for example, x+y//f means f[x+y], not x+f[y].
The prefix form @ has a much higher precedence. f@x+y is equivalent to f[x]+y, not f[x+y]. You can write f[x+y] in prefix form as f@(x+y).
Since lists are just a particular kind of expression, it will come as no surprise that you can refer to parts of any expression much as you refer to parts of a list.
You can refer to parts of an expression such as f[g[a],g[b]] just as you refer to parts of nested lists.
You should realize that the assignment of indices to parts of expressions is done on the basis of the internal Wolfram Language forms of the expression, as shown by FullForm. These forms do not always correspond directly with what you see printed out. This is particularly true for algebraic expressions, where the Wolfram Language uses a standard internal form, but prints the expressions in special ways.
This replaces the third part of a+b+c+d by x^2. Note that the sum is automatically rearranged when the replacement is done:
Part[expr,n] or expr[[n]] | the th part of expr |
Part[expr,{n1,n2,…}] or expr[[{n1,n2,…}]] | |
a combination of parts of an expression | |
Part[expr,n1;;n2] | parts through of an expression |
ReplacePart[expr,n->elem] | replace the th part of expr by elem |
"Manipulating Elements of Lists" discusses how you can use lists of indices to pick out several elements of a list at a time. You can use the same procedure to pick out several parts in an expression at a time.
Any part in an expression can be viewed as being an argument of some function. When you pick out several parts by giving a list of indices, the parts are combined using the same function as in the expression.
You can use most of the list operations discussed in "Lists" on any kind of Wolfram Language expression. By using these operations, you can manipulate the structure of expressions in many ways.
You should remember that all functions which manipulate the structure of expressions act on the internal forms of these expressions. You can see these forms using FullForm[expr]. They may not be what you would expect from the printed versions of the expressions.
You can add an argument using Append:
There are a few extra functions that can be used with expressions, as discussed in "Structural Operations".
TreeForm prints out expressions to show their "tree" structure:
You can think of any Wolfram Language expression as a tree. In the expression above, the top node in the tree consists of a Plus. From this node come two "branches", x^3 and (1+x)^2. From the x^3 node, there are then two branches, x and 3, which can be viewed as "leaves" of the tree.
The indices that label each part of an expression have a simple interpretation in terms of trees. Descending from the top node of the tree, each index specifies which branch to take in order to reach the part you want.
The Part function allows you to access specific parts of Wolfram Language expressions. But particularly when your expressions have fairly uniform structure, it is often convenient to be able to refer to a whole collection of parts at the same time.
Levels provide a general way of specifying collections of parts in Wolfram Language expressions. Many Wolfram Language functions allow you to specify the levels in an expression on which they should act.
Position[expr,form,n] | give the positions at which form occurs in expr down to level n |
Position[expr,form,{n}] | give the positions exactly at level n |
Controlling Position using levels.
You can think of levels in expressions in terms of trees. The level of a particular part in an expression is simply the distance down the tree at which that part appears, with the top of the tree considered as level 0.
It is equivalent to say that the parts which appear at level n are those that can be specified by a sequence of exactly n indices.
n | levels 1 through n |
Infinity |
all levels (except 0)
|
{n} | level n only |
{n1,n2} | levels n1 through n2 |
Heads->True | include heads |
Heads->False | exclude heads |
Level[expr,lev] | a list of the parts of expr at the levels specified by lev |
Depth[expr] | the total number of levels in expr |
When you have got the hang of ordinary levels, you can try thinking about negative levels. Negative levels label parts of expressions starting at the bottom of the tree. Level -1 contains all the leaves of the tree: objects like symbols and numbers.
You can think of expressions as having a "depth", as shown by TreeForm. In general, level -n in an expression is defined to consist of all subexpressions whose depth is n.