Up | Next | Prev | PrevTail | Tail |
Unlike substitutions introduced via sub, let rules are global in scope and stay in effect until replaced or cleared.
The simplest use of the let statement is in the form
where \(\langle \)substitution list\(\rangle \) is a list of rules separated by commas, each of the form:
or
or
For example,
let {x => y^2, h(u,v) => u - v, cos(pi/3) => 1/2, a*b => c, l+m => n, w^3 => 2*z - 3, z^10 => 0}
The list brackets can be left out if preferred. The above rules could also have been entered as seven separate let statements.
After such let rules have been input, x will always be evaluated as the square of Y, and so on. This is so even if at the time the let rule was input, the variable y had a value other than y. (In contrast, the assignment x:=y^2 will set x equal to the square of the current value of y, which could be quite different.)
The rule let a*b=c means that whenever a and b are both factors in an expression their product will be replaced by c. For example, a^5*b^7*w would be replaced by c^5*b^2*w.
The rule for l+m will not only replace all occurrences of l+m by n, but will also normally replace l by n-m, but not m by n-l. A more complete description of this case is given in Section 11.2.5.
The rule pertaining to w^3 will apply to any power of w greater than or equal to the third.
Note especially the last example, let z^10=0. This declaration means, in effect: ignore the tenth or any higher power of z. Such declarations, when appropriate, often speed up a computation to a considerable degree. (See Section 11.4 for more details.)
Any new operators occurring in such let rules will be automatically declared operator by the system, if the rules are being read from a file. If they are being entered interactively, the system will ask Declare… operator? (Y or N) . Answer Y or N and hit Return.
In each of these examples, substitutions are only made for the explicit expressions given; i.e., none of the variables may be considered arbitrary in any sense. For example, the command
let h(u,v) = u - v;
will cause h(u,v) to evaluate to u - v, but will not affect h(u,z) or h with any arguments other than precisely the symbols u,v.
These simple let rules are on the same logical level as assignments made with the := operator. An assignment x := p+q cancels a rule let x = y^2 made earlier, and vice versa.
CAUTION: A recursive rule such as
let x = x + 1;
is erroneous, since any subsequent evaluation of x would lead to a non-terminating chain of substitutions:
x -> x + 1 -> (x + 1) + 1 -> ((x + 1) + 1) + 1 -> ...
Similarly, coupled substitutions such as
let l = m + n, n = l + r;
would lead to the same error. As a result, if you try to evaluate an x, l or n defined as above, you will get an error such as
x improperly defined in terms of itself
Array and matrix elements can appear on the left-hand side of a let statement. However, because of their instant evaluation property, it is the value of the element that is substituted for, rather than the element itself. E.g.,
array a(5); a(2) := b; let a(2) = c;
results in b being substituted by c; the assignment for a(2) does not change.
Finally, if an error occurs in any equation in a let statement (including generalized statements involving for all and such that), the remaining rules are not evaluated.
If a substitution for all possible values of a given argument of an operator is required, the declaration for all may be used. The syntax of such a command is
e.g.,
for all x,y let h(x,y) = x-y; for all x let k(x,y) = x^y;
The first of these declarations would cause h(a,b) to be evaluated as a-b, h(u+v,u+w) to be v-w, etc. If the operator symbol h is used with more or fewer argument places, not two, the let would have no effect, and no error would result.
The second declaration would cause k(a,y) to be evaluated as a^y, but would have no effect on k(a,z) since the rule didn’t say for all y….
Where we used x and y in the examples, any variables could have been used. This use of a variable doesn’t affect the value it may have outside the let statement. However, you should remember what variables you actually used. If you want to delete the rule subsequently, you must use the same variables in the clear command.
It is possible to use more complicated expressions as a template for a let statement, as explained in the section on substitutions for general expressions. In nearly all cases, the rule will be accepted, and a consistent application made by the system. However, if there is a sole constant or a sole free variable on the left-hand side of a rule (e.g., let 2=3 or for all x let x=2), then the system is unable to handle the rule, and the error message
Substitution for ... not allowed
will be issued. Any variable listed in the for all part will have its symbol preceded by an equal sign: x in the above example will appear as =x. An error will also occur if a variable in the for all part is not properly matched on both sides of the let equation.
If a substitution is desired for more than a single value of a variable in an operator or other expression, but not all values, a conditional form of the for all … let declaration can be used.
Example:
for all x such that numberp x and x<0 let h(x)=0;
will cause h(-5) to be evaluated as 0, but h of a positive integer, or of an argument that is not an integer at all, would not be affected. Any boolean expression can follow the such that keywords.
The user may remove all assignments and substitution rules from any expression by the command clear, in the form
e.g.
clear x, h(x,y);
Because of their instant evaluation property, array and matrix elements cannot be cleared with clear. For example, if a is an array, you must say
a(3) := 0;
rather than
clear a(3);
to “clear” element a(3).
On the other hand, a whole array (or matrix) a can be cleared by the command clear a; This means much more than resetting to 0 all the elements of a. The fact that a is an array, and what its dimensions are, are forgotten, so a can be redefined as another type of object, for example an operator.
If you need to clear a variable whose name must be computed, see the unset statement.
The more general types of let declarations can also be deleted by using clear. Simply repeat the let rule to be deleted, using clear in place of let, and omitting the equal sign and right-hand part. The same dummy variables must be used in the for all part, and the boolean expression in the such that part must be written the same way. (The placing of blanks doesn’t have to be identical.)
Example: The let rule
for all x such that numberp x and x<0 let h(x)=0;
can be erased by the command
for all x such that numberp x and x<0 clear h(x);
clear is not the only way to delete a let rule. A new let rule identical to the first, but with a different expression after the equal sign, replaces the first. Replacements are also made in other cases where the existing rule would be in conflict with the new rule. For example, a rule for x^4 would replace a rule for x^5. The user should however be cautioned against having several let rules in effect that relate to the same expression. No guarantee can be given as to which rules will be applied by REDUCE or in what order. It is best to clear an old rule before entering a new related let rule.
The examples of substitutions discussed in other sections have involved very simple rules. However, the substitution mechanism used in REDUCE is very general, and can handle arbitrarily complicated rules without difficulty.
The general substitution mechanism used in REDUCE is discussed in [Hea68], and [Hea69]. For the reasons given in these references, REDUCE does not attempt to implement a general pattern matching algorithm. However, the present system uses far more sophisticated techniques than those discussed in the above papers. It is now possible for the rules appearing in arguments of let to have the form
where any rule to which a sensible meaning can be assigned is permitted. However, this meaning can vary according to the form of \(\langle \)substitution expression\(\rangle \). The semantic rules associated with the application of the substitution are completely consistent, but somewhat complicated by the pragmatic need to perform such substitutions as efficiently as possible. The following rules explain how the majority of the cases are handled.
To begin with, the \(\langle \)substitution expression\(\rangle \) is first partly simplified by collecting like terms and putting identifiers (and kernels) in the system order. However, no substitutions are performed on any part of the expression with the exception of expressions with the instant evaluation property, such as array and matrix elements, whose actual values are used. It should also be noted that the system order used is not changeable by the user, even with the korder command. Specific cases are then handled as follows:
let 2*x*y=3
becomes
let x*y=3/2
so that x*y is added to the product substitution table, and when this rule is applied, the expression x*y becomes 3/2, but X or Y by themselves are not replaced.
let l+m=n, x/2=y, a-b=c
become
let l=n-m, x=2*y, a=c+b.
One problem that can occur in this case is that if a quantified expression is moved to the right-hand side, a given free variable might no longer appear on the left-hand side, resulting in an error because of the unmatched free variable. E.g.,
for all x,y let f(x)+f(y)=x*y
would become
for all x,y let f(x)=x*y-f(y)
which no longer has y on both sides.
The fact that array and matrix elements are evaluated in the left-hand side of rules can lead to confusion at times. Consider for example the statements
array a(5); let x+a(2)=3; let a(3)=4;
The left-hand side of the first rule will become x, and the second 0. Thus the first rule will be instantiated as a substitution for x, and the second will result in an error.
The order in which a list of rules is applied is not easily understandable without a detailed knowledge of the system simplification protocol. It is also possible for this order to change from release to release, as improved substitution techniques are implemented. Users should therefore assume that the order of application of rules is arbitrary, and program accordingly.
After a substitution has been made, the expression being evaluated is reexamined in case a new allowed substitution has been generated. This process is continued until no more substitutions can be made.
As mentioned elsewhere, when a substitution expression appears in a product, the substitution is made if that expression divides the product. For example, the rule
let a^2*c = 3*z;
would cause a^2*c*x to be replaced by 3*z*x and a^2*c^2 by 3*z*c. If the substitution is desired only when the substitution expression appears in a product with the explicit powers supplied in the rule, the command match should be used instead..
For example,
match a^2*c = 3*z;
would cause a^2*c*x to be replaced by 3*z*x, but a^2*c^2 would not be replaced. match can also be used with the for all constructions described above.
To remove substitution rules of the type discussed in this section, the clear command can be used, combined, if necessary, with the same for all clause with which the rule was defined, for example:
for all x clear log(e^x),e^log(x),cos(w*t+theta(x));
Note, however, that the arbitrary variable names in this case must be the same as those used in defining the substitution.
Up | Next | Prev | PrevTail | Front |