I want a function which creates a rule. The rule is of the form
"manipulated input" -> "input". Here is my first attempt (I have
simplified from what I really want to do, in order to illustrate the
bug):
(1) makerule[input_] :=(input /. a_Integer :> 2 a) -> input
In: makerule[5]
Out: 2a->5
(I expect to get 10->5)
(2) makerule2[input_] := (input /. a_Integer :> 2 a)~myrule~input
In: makerule2[5]
Out: myrule[10,5]
as expected
Forcing an extra layer of localization seems to squash the bug:
(3) makerule3[input_] :=Block[{inputcopy = input},(input /.
a_Integer :> 2 a) -> inputcopy]
In: makerule[5]
Out: 10->5
Is it a bug, or have I misunderstood how the localization is meant to
work?
makerule[input_] := Rule[(input /. a_Integer :> 2 a), input];
Trace@makerule[5]
You will see that the first a is localized, the second not. There
seems to be a problem with nested rules. I would report this to
Wolfram.
Daniel
This is gonna be one of these weird Mathematica features that surprise
me every day. I played around with your code (Mathematica 6.0.2) and
this occurs for any of the lexical scoping constructs: function
definition, rule and With. But only when the value is inserted in the
right-hand side of a rule, as in:
With[{x = 2}, (2 /. a_ :> 2 a) :> x]
but not in
With[{x = 2}, (x /. a_ :> 2 a) :> 2]
One can see what is happening using Trace:
In[1]:= Trace[With[{x=2},(2/.a_:>2a):> x]]//Column
Out[1]=
With[{x=2},(2/.a_:>2 a):>x]
(2/.a$_:>2 a):>2
{{a$_:>2 a,a$_:>2 a},2/.a$_:>2 a,2 a}
2 a:>2
2 a:>2
You can see that the localization renames a to a$, but only on the
left-hand side of the rule. And this is imho wrong.
Even simpler:
In[2]:= Trace[With[{x=2},(a_:>a):> x]]//Column
Out[2]=
With[{x=2},(a_:>a):>x]
(a$_:>a):>2
{a$_:>a,a$_:>a}
(a$_:>a):>2
(a$_:>a):>2
but
In[3]:= Trace[With[{x=2}, a_:>a x]]//Column
Out[3]= With[{x=2},a_:>a x]
a$_:>a$ 2
which gives the correct result, even though the renaming is completely
unnecessary. Compare with
In[4]:= Trace[With[{x=2}, x a_:>a ]]//Column
Out[4]= With[{x=2},x a_:>a]
2 a_:>a
No renaming.
Very interesting ;))
Best,
Norbert
This indeed looks like a bug to me. Tracing the execution allows to reveal
some details:
In[1]:= makerule[5]//Trace
Out[1]= {makerule[5],(5/.a$_Integer:>2 a)->5,{{a$_Integer:>2 a,a$_Integer:>2
a},5/.a$_Integer:>2 a,2 a},2 a->5,2 a->5}
The real problem is that <input> is present in the definition *and*
the both sides of the rule <(input /. a_Integer :> 2 a) -> input>. It is
well-known that Mathematica does aggressive dummy (pattern) variable
renaming whenever it suspects a name collision in nesting lexical scoping
constructs. Both Rule and RuleDelayed are scoping constructs, therefore
placing rule within a rule where some of the pattern names are present in
both external and internal rules (<input> in this case) is an invitation for
the Mathematica variable-renaming mechanism. In this case, however, the
renaming was obviously inconsistent - <a> was renamed to <$a> only on the
left-hand side of the delayed rule.
My guess would be that the binding in the internal RuleDelayed is performed
at an earlier stage, since in nesting the scoping constructs the usual
Mathematica convention is that inner scopes are favored in name collisions
(but again, Rule and RuleDelayed do not always obey this convention). Then
<a> gets replaced by <$a> indeed everywhere, but then the just mentioned
internal binding sets the r.h.s. back to <a>. Regardless of whether or not
this is indeed what happens, the final result is IMO not what it should have
been.
It is easy to see that the problem shows up "dynamically" during the rule
application rather than when the definition is given:
In[2]:= Hold[makerule[5]] /. DownValues[makerule]
Out[2]= Hold[(5 /. a$_Integer :> 2 a) -> 5]
Why the same did not happen in the second case is beyond me. Perhaps
wrapping your numbers in <myrule> means for RuleDelayed that there is no
nesting of scoping, since <myrule> is not a scoping construct (while Rule is
a scoping construct and thus there is direct nesting), and therefore
renaming is not attempted.
In the last case you seem to have blinded the renaming mechanism by using
Block (the latter being a dynamic scoping construct).
In any case, this looks like a bug.
Regards,
Leonid
Clear[makerule]
makerule[input_Integer] :=
2*input -> input
makerule /@ {5, 5 x}
{10->5,makerule(5 x)}
Clear[makerule]
makerule[input_] :=
input /. a_Integer :> (2 a -> a)
makerule /@ {5, 5 x}
{10->5,x (10->5)}
Bob Hanlon
---- Derek Yates <yat...@mac.com> wrote:
=============
I asked about odd behavior this in-house yesterday. Either someone will
give a plausible explanation, or it will get filed as a bug report.
Daniel Lichtblau
Wolfram Research
Bobby
On Thu, 31 Dec 2009 02:16:00 -0600, Norbert P. <berta...@gmail.com>
wrote:
> On Dec 30, 1:16 am, Derek Yates <yat...@mac.com> wrote: