7
$\begingroup$

It is customary to use the following idiom to partially evaluate something inside a held expression:

f[x_] := 2 x
Block[{f}, Hold[f[1 + 1]] /. x_f :> With[{r = x}, r /; True]]

Out[]= Hold[f[2]]

This works also with built-in symbols, like

Block[{Abs}, Hold[Abs[1 + 1]] /. x_Abs :> With[{r = x}, r /; True]]

Out[]= Hold[Abs[2]]

However, I cannot understand the behaviour of the following

Block[{Plus}, Hold[1 + 2*2] /. x_Plus :> With[{r = x}, r /; True]]

which returns Hold[5] instead of Hold[1+4]. Can someone explain why?

$\endgroup$
7
$\begingroup$

I think my answer to Why does this pattern with Plus not work for numbers? is also the answer here.


See Plus in the reference manual:

Unlike other functions, Plus applies built-in rules before user-defined ones. As a result, it is not possible to make definitions such as 2+2=5.

The ability for user-defined rules to supersede built-in ones was lost in Version 3.


There is a similar property for Times.

Here is some evidence that rules for Plus are applied internally even when Plus is blocked:

Block[{Plus}, 1 + 2*2 /. Plus -> List]
(*  5  *)

p[x__] := Plus[x];
Block[{p}, p[1, 2*2] /. p -> List]
(*  {1, 4}  *)

Update -- some more evidence:

Block[{Plus}, 
  Hold[1 + 2*2] /. x_Plus :> With[{r = x}, r /; True]] // Trace

Mathematica graphics

Block[{p}, 
  Hold[p[1, 2*2]] /. x_p :> With[{r = x}, r /; True]] // Trace

Mathematica graphics

$\endgroup$
  • $\begingroup$ Michael, I marked this question as a duplicate. Please let me know if you disagree. Also I suspect you meant to link to 19126 rather than 3261 when you wrote "my answer to ..." $\endgroup$ – Mr.Wizard Aug 4 '15 at 1:40
  • $\begingroup$ @Mr.Wizard I don't disagree. I considered proposing it, but I wasn't sure I had nailed the reason. -- And thanks, for pointing out I had copied the wrong link! $\endgroup$ – Michael E2 Aug 4 '15 at 1:43
  • $\begingroup$ It occurs to me that I have a work-around that is applicable here but not in the original as marked. Do you think I should reopen for that or just append it here in passing? $\endgroup$ – Mr.Wizard Aug 4 '15 at 1:49
  • $\begingroup$ @Mr.Wizard If it were me with such a work-around, I would probably nominate for re-opening. (I have done so in the past.) But it's up to you. $\endgroup$ – Michael E2 Aug 4 '15 at 1:54
  • $\begingroup$ I posted. Let me know what you think or if you find problems with it, please. $\endgroup$ – Mr.Wizard Aug 4 '15 at 5:46
3
$\begingroup$

I closed this as a duplicate of Why does this pattern with Plus not work for numbers? but I think I have something that is general enough to be useful, and it's not applicable to that question.

We may observe that although a plain use of Block[{Plus}, . . .] does not prevent numeric evaluation of Plus we can still make a substitution that does:

Block[{Plus = plus}, Hold @@ {2 + 2}]
Hold[plus[2, 2]]

From there we could replace plus with Plus again. Automating this process:

Attributes[hardBlock] = {HoldAll};

hardBlock[sym : {___Symbol}, body_] :=
  Block[sym, sym = #; body] /. Thread[# :> sym] & @ Module[sym, sym]

Now:

expr := Hold @@ {1 + 2 + 3*4}

Block[{Plus, Times}, expr]   (* original Block behavior for reference *)

hardBlock[{Plus},        expr]
hardBlock[{Times},       expr]
hardBlock[{Plus, Times}, expr]
Hold[15]

Hold[1 + 2 + 12]
Hold[3 + 3 4]
Hold[1 + 2 + 3 4]

And for completeness:

hardBlock[{Plus}, Hold[1 + 2*2] /. x_Plus :> With[{r = x}, r /; True]]
Hold[1 + 2 2]
$\endgroup$
  • 1
    $\begingroup$ Have you looked at hardBlock[{Plus}, Hold[1 + 2*2] /. x_Plus :> With[{r = x}, r /; True]] // Trace? I think the Plus inside Hold is neither changed nor replaced. Consider hardBlock[{Plus}, Hold[1 + 2*2] /. HoldPattern[x_Plus] :> With[{r = x}, r /; True]] instead. (The thing that made me wonder was that 2*2 did not become 4.) $\endgroup$ – Michael E2 Aug 4 '15 at 11:13
  • $\begingroup$ @Michael Thank you! I worried there would be problems like that I had failed to think through. I'll have to consider how this case might be improved, or if this construct still has a purpose. :-/ $\endgroup$ – Mr.Wizard Aug 4 '15 at 18:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.