I'm trying to use Block
to prevent a function from executing. In this example, the function I'm trying to block will simply be Plus
. My code has an inner With
clause inside the Block
. The With
clause performs some operations itself, and also receives an expression passed-in as a function parameter. In the below example, I emulate that with an outer With
clause.
Unexpectedly, for a simple two-operand Plus
, Block
is only blocking Plus
for the expression passed-in to the inner With
clause, not the Plus
operation hard-coded into the With
clause. For a three-operand Plus
, it blocks everything.
A canonical code sample which produces this behavior is shown below. Any ideas? I may switch to using Inactivate
for my real problem, though I have to think it through a bit more. Thanks!
EDIT: Changed example to Print
the results instead of Hold
'ing them, as the Hold[#]& @ ...
syntax required to illustrate the "extent of execution within the Block
" was obfuscating my intent.
With[{a := 1 + 2},
Block[{Plus}, SetAttributes[{Plus}, HoldAllComplete];
With[{x := {a + 3 + 4, a*2*2}, y := {a + 3 + (4 + 5), a*2*2}},
Print["x: ", x];
Print["Unevaluated@x: ", Unevaluated@x];
Print["y: ", y];
Print["Unevaluated@y: ", Unevaluated@y];
]]]
Results:
x: {7+(1+2),12}
Unevaluated@x: {(1+2)+3+4,(1+2)*2*2}
y: {3+(1+2)+(4+5),12}
Unevaluated@y: {(1+2)+3+(4+5),(1+2)*2*2}
EDIT:
Expected results:
x: {(3+4)+(1+2),(1+2)*4} (* DELTA *)
Unevaluated@x: {(1+2)+3+4,(1+2)*2}
y: {3+(1+2)+(4+5),(1+2)*4} (* DELTA *)
Unevaluated@y: {(1+2)+3+(4+5),(1+2)*2}
My real code has to do with code injection into held expressions.
EDIT: Another simplified example (Thanks @PierreALBARÈDE):
Block[{Plus}, Attributes[Plus] = {HoldAllComplete};
Print /@ {Plus[1, 2], Plus[1, 2, 3], Plus[1 + 2, 0],
Plus[1 + 2 + 3, 0]};]
Results:
3
6
1+2
1+2+3
It seems that only the HoldAllComplete
attribute is doing anything...
Plus
andTimes
have internal rules that are applied before the standard evaluation cycle. You cannot override them. It does not say what they are exactly, so they may or may not be the cause of the trouble. $\endgroup$Inactivate[expr,Plus]
instead ofBlock[{Plus},expr]
behave differently, and that the two-operand vs three-operand versions ofPlus
behave differently, but like you say... it could be some oddity of the internal rules. $\endgroup$Unprotect
orBlock
, I always think "No. Don't do that. Find another way to get what you need." It's just not an approach that can be made to work reliably. $\endgroup$