It is documented that "Block is automatically used to localize values of iterators in iteration constructs such as Do, Sum, and Table." Therefore the dummy index (iterator) in a Sum is shielded against a global variable with the same name, for example:
k = 123;
Sum[f[k] + f[k], {k, -Infinity, Infinity}]
gives the result:
Sum[2*f[k], {k, -Infinity, Infinity}]
I am creating my own version of the Sum command, this is the way I thought Block[] had to be used:
SetAttributes[mySum, HoldAll];
mySum[arg_, {index_Symbol, limits___}] :=
Block[{index, evaluatedarg},
Print["debug msg 1"];
evaluatedarg = arg;
With[{replaceevaluated = evaluatedarg},
mySum[replaceevaluated, {index, limits}] /;
HoldComplete[replaceevaluated] =!= HoldComplete[arg]]
];
However the "index" variable inside Block[] becomes red, Mathematica showing a scoping conflict that I do not see. Now, it gives the correct result, but the problem is that the function gets called several times (instead of only two times, as I was expecting), as in this sample run:
k = 8;
mySum[f[k] + f[k], {k, -Infinity, Infinity}]
which gives the output:
debug msg 1
debug msg 1
debug msg 1
debug msg 1
debug msg 1
debug msg 1
mySum[2 f[k], {k, -\[Infinity], \[Infinity]}]
It is bad that the function gets called so many times, because when it is part of a large expression, with nested sums and other algebraic manipulations, the calculation becomes too slow to be useful. It seems this behavior is because of the scoping problem in the index variable, because if I rename the index inside Block to index2 (which of course destroys the scoping I wanted) and run in a fresh Mathematica session, the message is only printed twice (the first time when the rule is really applied, and the second time when it is determined that the rule does not apply for the new mySum). So my questions are a)How does the scoping problem make the function to be called more than twice?, but more important for me b)What is the correct way to implement the "Block" behavior in the command mySum so it works like the standard Sum command?
Sum
? Would it be possible to use e.g. upvalues instead, to "overload" the behavior of the built in function and deal with your objects? $\endgroup$mSum[body_, {index_Symbol, limits__}] /; Block[{index}, HoldForm[body] =!= body] := Block[{index}, mSum[Evaluate[body], {index, limits}]]
, but this gives me recursion and iteration limit errors. ATrace
reveals that at the second recursion ofmSum[f[k]+f[k],{k,-Infinity,Infinity}]
, MMA evaluates{2 f[k] =!= 2 f[k], True}
which I cannot understand $\endgroup$Block
by the top-level rule (your function), rather than being the actual symbol. In most cases, things like that happen due to a programmer's mistake, which is why there is a warning. But in your case, you do want to useBlock
exactly like that. Also, while there is a warning, in the case ofBlock
the outerSetDelayed
won't attempt to rename variables, sinceBlock
is a dynamic rather than lexical scoping construct - so you don't have to worry about that either. $\endgroup$mySum[arg_, {index_Symbol, limits___}] /; ! ValueQ[evaluatedarg] :=...
instead ofmySum[arg_, {index_Symbol, limits___}]
. I don't see how you can further reduce the call number, off hand - but it might be possible, of course. $\endgroup$