An atomic expression is either a constant (e.g., 37, true) or a variable (e.g., x, p).
A compound expression has one or more subexpressions, like this:
Often, one or more pairs of parentheses in an expression can be omitted, based upon agreed-upon properties of operators, including precedence and associativity. This tends to make expressions easier to read.
Examples:
- / \ / \ / \ / \ + · / \ / \ / \ / \ · 3 7 y / \ / \ 2 x |
Expression Evaluation:
To evaluate an expression, we first replace every occurrence of a variable
in the expression by its value, resulting in an expression in which every
atomic subexpression is a constant. Then we repeatedly evaluate
immediadely evaluable compound subexpressions (each time
replacing the evaluated subexpression by a constant) until such time
as the entire expression has been reduced to a constant.
An immediately evaluable compound subexpression is one of the
form E op F, where each of E and F is a
constant. Example: 13 / 5.
But how do we know the value of each variable? Ah, this gives rise to the notion of state, which is a mapping from variables to values. (Consider the use of the term state in the context of object-oriented programming. An object's state is determined by the values of its instance variables.)
If the state in which an expression is to be evaluated is incomplete with respect to that expression (i.e., one or more of the variables in the expression are not in the domain of the state), then the expression cannot be fully evaluated. Well, usually.
Some expressions have a value that does not depend upon the state in which they are evaluated. Examples: x = x and p ∧ ¬ p evaluate to true and false, respectively, regardless of the state.
As an example, suppose we were to evaluate the expression 2x - y in a state in which x has value 7 and y has value 3. Then to evaluate 2x - y we "plug in" 7 in place of x and 3 in place of y, yielding 2·7 - 3, which simplifies to 11 upon applying the multiplication and then subtraction operators.
Gries's notation is E[x := R], which refers to the result of replacing, within expression E, each occurrence of variable x by expression (R). (Depending upon the context in which x occurs in E, the parentheses surrounding R can be omitted.)
In a substitution [x := R], x can be a list of variables (necessarily distinct from one another), in which case R must be a list of expressions of the same length. In this case, the substitutions are applied simultaneously (as opposed to sequentially).
Examples:
Expression | Result | Remarks |
---|---|---|
x[x := x+2] | x+2 | outermost () omitted |
y[x := x+2] | y | there is no occurrence of x to replace |
x − y[x := x+2] | x − y | textual substitution binds more strongly than any operator |
(x − y)[x := x+2] | x + 2 − y | parentheses around x+2 omitted |
(x · y)[x := x+2] | (x + 2) · y | parentheses around x+2 needed because · binds more tightly than + |
(5x2 + 7x − 1)[x := x+2] | 5(x+2)2 + 7(x+2) − 1 | multiple occurrences of x |
(x + y)[x,y := 2z,x] | 2z + x | simultaneous substitution of multiple variables |
(x + y)[x,y := 2y,x] | 2y + x | compare with the following |
(x + y)[x := 2y][y := x] | 2x + x | two substitutions done sequentially |
Textual subsitution is left associative, which is to say that E[x := R][y := S] means the same thing as (E[x := R])[y := S]. That is, we first apply the substitution [x := R] to E and then we apply the substitution [y := S] to the resulting expression.
As the last two examples illustrate, a simultaneous substitution can yield a different result than doing the same substitutions in sequence.
Hidden Variables
It is often convenient to give a name to an expression and to use
that name within a larger expression. For example, we might
use A as a name for the expression b2 − 4ac
and use it in the larger expression A ≥ 0. If we then apply the
textual substitution (A ≥ 0)[a,b,c := 3,4,1], we must be sure
to replace the "hidden" variables a, b, and c within A by 3, 4, and 1,
respectively.
Inference Rule Substitution
Recall that an inference rule provides a way to generate
"new" theorems from "already-existing" theorems.
The standard format for describing an inference rule is
A |
B |
where A is a list of premises and B is the conclusion. What it means is that if each item in A is a theorem, then B is also a theorem.
Our first rule of inference is
Substitution: | E |
---|---|
E[v := F] |
This rule asserts that if E is a theorem, then so is any expression that can be obtained by replacing, within E, any variable v by any expression F. (Recall that v and F can be lists of variables and expressions, respectively.)
As an example, consider the theorem x + y = y + x from arithmetic, which expresses the commutativity of addition. If we replace x by b−7 and y by 4, we get b − 7 + 4 = 4 + b − 7, which one might view as being a more particular example of addition's commutativity.
What we have done here is to instantiate the Substitution rule of inference as follows:
Thus we see that Substitution is really a "scheme" that represents an infinite set of rules, because we can instantiate it in any way that we wish (by choosing whatever we want for E, v, and F).
An example from propositional logic is as follows: Choose E to be p ∨ ¬p, v to be p, and F to be q∧p. This instantiation results in this rule:
p ∨ ¬p |
(q ∧ p) ∨ ¬(q ∧ p) |