Re: Which inside Module causes problems with ReplaceAll
- To: mathgroup at smc.vnet.net
- Subject: [mg111391] Re: Which inside Module causes problems with ReplaceAll
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Fri, 30 Jul 2010 06:56:36 -0400 (EDT)
Hi, This is a result of what can be called a variable capture, which is a feature that can bring both benefits and problems, depending on the situation. For this particular case: Which can return unevaluated, if it can not determine whether the condition is True or False (just as If). Now, here: In[1]:= test[x_] := Module[{u}, Which[x == 0, 0, True, u[t_] := t^2; u[x]]] You use == (Equals) . Therefore, on generic symbolic argument like <t>, we get: In[2]:= test[t] Out[2]= Which[t == 0, 0, True, u$2541[t_] := t^2; u$2541[t]] Since Which did not evaluate, <u> did not yet receive its definition. The next observation is that RuleDelayed and Rule are perhaps the only scoping constructs in Mathematica (sometimes Function is also) which do not respect the bindings of inner scoping constructs during the variable name conflict resolution. Therefore, in this particular case, you indeed replace <t> everywhere with <3>, which results in an error, since t gets replaced by 3 even before u$2541[t_] := t^2; executes. I think, in some sense this can be considered a bug, or at the very least, a very non-intuitive behavior. Now, a couple workarounds. One is to restrict the input values or your function to say only numerical values: Clear[test]; test[x_?NumericQ] := Module[{u}, Which[x == 0, 0, True, u[t_] := t^2; u[x]]] In[12]:= test[t] /. t -> 3 Out[12]= 9 This is a point solution however, while this situation occurs every now and then and is quite annoying. Here is a more general solution that I wrote for my own use some time ago. I use it in cases when i want to be absolutely sure that my variables are properly localized, and when I have a mix of local functions and rules similar to your example. This is a macro that processes your code and systematically renames variables in definitions of the form f[args__]:=r.h.s.: ClearAll[protectDefs]; SetAttributes[protectDefs, HoldAll]; protectDefs[code_] := Module[{myHold}, SetAttributes[myHold, HoldAll]; ReleaseHold[Replace[Hold[code], def : Verbatim[SetDelayed][ h_[args : Verbatim[Pattern][_Symbol, ___] ..], rhs_] :> With[{eval = With[{rules = Cases[{args}, Verbatim[Pattern][s_Symbol, ___] :> (s -> Unique[]), Infinity]}, myHold[def] /. rules]}, eval /; True], {0, Infinity}] //. myHold[x__] :> x]] Here is how you can use it: protectDefs[ Clear[test]; test[x_]:= Module[{u}, Which[x==0,0,True,u[t_]:=t^2; u[x]]] ] ?test Global`test test[$15_]:=Module[{u},Which[$15==0,0,True,u[$14_]:=$14^2;u[$15]]] In[74]:= test[t] /. t -> 3 Out[74]= 9 You can also break it if you really want: In[75]:= test[$14] /. $14 -> 3 During evaluation of In[75]:= Pattern::patvar: First element in pattern Pattern[3,_] is not a valid pattern name. >> Out[75]= u$2821[3] But this is much less likely to happen inadvertently. Hope this helps. Regards, Leonid On Thu, Jul 29, 2010 at 2:44 PM, P. Fonseca <public at fonseca.info> wrote: > Hi, > > Version 7.0.1 > > This works: > > In[7]:= test[x_]:=Module[{u}, > u[t_]:=t^2; > u[x]] > > In[8]:= test[t]/.t->3 > > Out[8]= 9 > > > > > This doesn't: > > In[9]:= test[x_]:=Module[{u}, > > Which[ > x==0,0, > > True, > u[t_]:=t^2; > u[x] > ] > ] > > In[10]:= test[t]/.t->3 > > During evaluation of In[10]:= Pattern::patvar: First element in > pattern Pattern[3,_] is not a valid pattern name. >> > Out[10]= u$670[3] > > > > What's going on? > > Regards, > P. Fonseca > > >