MathGroup Archive 1999

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Re: Scoping and named patterns

Hello Doctor,

I'd like to still give a little comment:

Dr Dan schrieb:
> In article <7kcjrn$lql at>,
>   Dr Dan <drdanw at> wrote:
> > I am having trouble with name conflicts between global symbols and
> > named patterns.
> >
> > This example from The Book works fine:
> >
> > In[1]:= f[a^b] /. f[x : _^n_] -> p[x, n]
> > Out[1]= p[a^b, b]
> >
> > But if the symbols used as pattern names have values:
> >
> > In[3]:= n = 2; x = 3;
> >         f[a^b] /. f[x : _^n_] -> p[x, n]
> > Out[3]= p[3, 2]
> >
> > My usual favorite scoping structure, Module, doesn't help:
> >
> > In[4]:= Module[{x, n}, f[a^b] /. f[x : _^n_] -> p[x, n]]
> > Out[4]= p[3, 2]
> >
> > This shows that the global symbol is used as the pattern name and not
> > the symbol local to the scoping construct:
> >
> > In[5]:= Module[{x, n}, Clear[x, n]; f[a^b] /. f[x : _^n_] -> p[x, n]]
> > Out[5]= p[3, 2]
> >
> > Since local symbols are ignored, it is necessary to use Block:
> >
> > In[6]:= Block[{x, n}, f[a^b] /. f[x : _^n_] -> p[x, n]]
> > Out[6]= p[a^b, b]
> >
> > This looks like a bug to me.  If I use a symbol in a local context I
> > expect the local symbol and never the global.  I am a little concerned
> > that the pattern itself doesn't scope its pattern names, that I can
> > make one seemingly small change in my notebook and my patterned
> > replacements begin crashing.
> >
> > Any comments, or a better workaround than Block?
> Just after posting the above message, I discovered that the Block
> solution doesn't always work.  My original intent was to store a
> complicated rule for use elsewhere in the notebook:

OK, then you have to be cautious *twice*, first when your rule is being
defined, second, when it is evaluated

> In[1]:= n = 2; x = 3;
> In[2]:= r = Block[{x, n},  f[x : _^n_] -> p[x, n]];
>         f[a^b] /. r
> Out[3]= p[3, 2]
> Oops.  Now my replacement is outside the block. ...... 

Yes, but the defintion of your rule too! To understand that, better do
single steps! If you define

In[4]:= r1=f[x:_^n_]->p[x,n];
In[5]:= ?r1
   r1 = f[x:_^(n_)] -> p[3, 2]

This is to be understood well: at time of definition the actual values
for x and n are substituted at the rhs of Rule. But if you do

In[7]:= r2=Block[{x,n},f[x:_^n_]->p[x,n]];
In[8]:= ?r2
    r2 = f[x:_^(n_)] -> p[3, 2]

You do get the *same*, why? Trace will show: Block indeed returns
unsubstituted values for x and n (since they are effectively cleared
inside Block), but the result of Block is then evaluated again *before*
r2 is set, and such the values of x and n creep in again. You'll get
your wanted rule if you Set *inside* of Block:

In[11]:= Block[{x,n},r3=f[x:_^n_]->p[x,n]]
Out[11]= f[x : _^n_] -> p[3, 2]
In[13]:= ?r3
    r3 = f[x:_^(n_)] -> p[x, n]

Now if you try 

In[31]:= f[a^b]/.r3
Out[31]= p[3,2]

you still don't get what you wanted. Again Trace will show you why: the
rhs of Rule r3 will be evaluated, before the pattern variables match,
and such 3 and 2 again come in still too early. But if you also evaluate
your rule inside Block, then

In[33]:= Block[{x,n},f[a^b]/.r3]
Out[33]= p[a^b, b]

> .....Then I stumbled upon
> the correct solution (without knowing why it worked), using RuleDelayed:
> In[4]:= r = f[x : _^n_] :> p[x, n];
>         f[a^b] /. r
> Out[5]= p[a^b, b]
> x_x
> This seems to be a robust solution.  Read the other postings in this
> thread for a much better explanation than I can give.  Thank you for
> the help.  

This is (mostly) the better way to do it, and there will be no
evaluation of x or n until the pattern variables are defined within the
scope of Rule, when it is applied. So there should be no need to do that
doubled Block-ing. However, when p[x,n] ist some complicated or costly
expression, it may be advantageous to evaluate it (once) at definition
time, instead of (possibly, over and over) when the rule is applied.

So with

In[80]:= zzz:=Do[Tan[ArcTan[Sqrt[Pi]]],{10000}]
In[81]:= zzz//Timing
Out[81]= {2.574 Second,Null}
In[82]:= q[x_,n_]:=(zzz;p[x,n])


In[83]:= (rx=f[x:_^n_]:>q[x,n])//Timing
Out[83]= {0. Second, f[x : _^n_] :> q[x, n]}
In[84]:= f[f[a^b]^f[c^d]]//.rx //Timing
Out[84]= {10.455 Second, p[p[a^b, b]^p[c\^d, d], p[c^d, d]]}


In[85]:= Block[{x,n},ri=f[x:_^n_]->q[x,n]]//Timing
Out[85]= {2.583 Second, f[x : _^n_] -> p[3, 2]}
In[86]:= Block[{x,n},f[f[a^b]^f[c^d]]//.ri ]//Timing
Out[86]= {0. Second, p[p[a^b, b]^p[c\^d, d], p[c^d, d]]}

But perhaps still the better way to do that would be:

In[91]:= Block[{x,n},rx2=f[x:_^n_]:>Evaluate[q[x,n]]]//Timing
Out[91]= {2.604 Second, f[x : _^n_] :> p[x, n]}
In[92]:= f[f[a^b]^f[c^d]]//.rx2 //Timing
Out[92]= {0. Second, p[p[a^b, b]^p[c^d, d], p[c^d, d]]}

Again you have to be careful to wrap the whole definition of rule rx2
within Block! But you'll need no Block-ing at rule application.

Regards, hw

  • Prev by Date: Re: problem with Part function
  • Next by Date: Livegraphics3D
  • Previous by thread: Re: Scoping and named patterns
  • Next by thread: why Developer` and Experimental` functions are not in Add-ons help