Read Online
Download PDF
Additional resources
Revision history
Known typos/bugs
Report a bug
License terms
About the author
"node346_1.gif" "node346_2.gif" "node346_3.gif"     Rule within a rule, and a better catchall solution for our example

Considering our initial problem, it is rather inconvenient to have so many rules for describing essentially some particular cases of a general situation : whenever literal < x > is an argument of some function, change it to < 10 > in that function. Let us see if we can write a more concise and general solution for this problem. The one that I suggest requires  BlankSequence.

Illustrating expression deconstruction

To illustrate how it works here, we will now create a rule which will "deconstruct"  our expressions according to this pattern :



The reason that I used a restricted pattern with  a condition f =!= List is that otherwise the whole list will match, since its elements match the pattern __ :



Restricted patterns we will cover later, for now just think of it as a pattern with a certain condition attached. At the same time, this example by itself shows that one has to be careful when defining patterns since the can match in more cases than we expect.

The solution to our problem

Returning to our initial problem, here is a solution:




1. Use parentheses to impose the correct precedence

This solution is remarkable in several aspects. First of all, we have used a rule within a rule, and the inner rule we used in parentheses. The meaning of this is : once we found anything that matches the pattern of the "first" (or "outer") rule, make a replacement in this expression according to the "second", or "inner" rule. The first ("outer") rule acts here essentially as a filter for a second ("inner") one. Should we omit the parentheses, and we would not get the desired result :



The reason this happened is that the rule application is left - associative. Thus, the first rule applied first, and was essentially idle, because it says by itself just f_[t__] /; f =!= List :> f[t], that is, replace an expression of this form by itself :



The second rule then applied to < step1 >, and it says : replace < x > by < 10 > whenever < x > occurs. Thus, for example, the first element of the list, which is just < x > and is not an argument of any function, also got replaced.



However, if we use the parentheses, we  ensure that the second rule is actually applied to the results "filtered" by the first rule.

2. Use RuleDelayed to supply correct arguments to the inner rule

The second subtlety here is that we used RuleDelayed instead of Rule for the first (outer) rule. It is easy to see that if we don' t , we will not get a desired result :



The reason is that in the case of Rule, the r.h.s. of the rule is evaluated before the rule is substituted. Recalling the general strategy of Mathematica evaluation, the inner rule will be evaluated before the outer one (this is what parentheses ensure). But by that time, the literal < t >  in the outer rule has yet no relation to the matched parts of the list whatsoever, and just remains the literal < t > . Thus, the rule < f[t] /. x -> 10 > is completely idle and evaluates to f[t]. This results then in just the first rule f_[t__] /; f =!= List ->f[t], which again is idle.

3. Confirmation : use Trace command

This description can be confirmed with the Trace command:



If we use RuleDelayed however, the r.h.s of the outer rule (which includes the inner rule) will not be evaluated until some match has been found for the outer rule. This will allow the inner rule to operate on expressions matched by the outer rule.

"node346_20.gif" "node346_21.gif" "node346_22.gif"

Created by Wolfram Mathematica 6.0  (05 February 2009) Valid XHTML 1.1!