       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:=
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:= test[t]

Out= 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:= test[t] /. t -> 3

Out= 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
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:= test[t] /. t -> 3

Out= 9

You can also break it if you really want:

In:= test[\$14] /. \$14 -> 3

During evaluation of In:= Pattern::patvar: First element in pattern
Pattern[3,_] is not a valid pattern name. >>

Out= u\$2821

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:= test[x_]:=Module[{u},
>        u[t_]:=t^2;
>        u[x]]
>
> In:= test[t]/.t->3
>
> Out= 9
>
>
>
>
> This doesn't:
>
> In:= test[x_]:=Module[{u},
>
>        Which[
>        x==0,0,
>
>        True,
>        u[t_]:=t^2;
>        u[x]
>        ]
>        ]
>
> In:= test[t]/.t->3
>
> During evaluation of In:= Pattern::patvar: First element in
> pattern Pattern[3,_] is not a valid pattern name. >>
> Out= u\$670
>
>
>
> What's going on?
>
> Regards,
> P. Fonseca
>
>
>

```

• Prev by Date: Re: SetAttributes for entire package
• Next by Date: Re: NDSolve - how to bypass safety chceck?
• Previous by thread: Re: Which inside Module causes problems with ReplaceAll
• Next by thread: Re: Which inside Module causes problems with ReplaceAll