# How to use replacement rules in a named expression before a sub-expression evaluates?

I have a named expression: expr := a + b. a and b are also named expressions.

Let's say a := x + y, b := z + w. This means that expr becomes x + y + z + w

At this point I want to replace Plus to Times in expr (but only in expr) to get (x+y)*(z+w).

Can this be done?

Additional info: I have no control over how any of the expressions are defined. Ultimately this boils down to:

a := x + y
expr := a + b
b := z + w
(* I have no control over the code above. The order is not defined. *)
magic[expr, Plus -> Times]
(* (x + y) (w + z) *)


Is magic possible to implement?

• It is a bit difficult to know what an evaluatable expression means. Maybe "How to use replacement rules before a sub expression evaluates ?" Dec 21, 2022 at 17:09
• @userrandrand granted. I edited the title Dec 21, 2022 at 18:43

## 4 Answers

You can do his using "Hold" and "ReleaseHold" to prevent temporarily the evaluation:

Clear[a, b, expr]
a := x + y; b := z + w;
expr := Hold[a + b  ] /. Plus -> Times // ReleaseHold
expr

(* (x + y) (w + z) *)


Addendum

If expr can not be changed and is given e.g as; "a+b" then you can get the expression from "OwnValues" using "Extract":

Clear[a, b, expr]
expr := a + b;
a := x + y; b := z + w;

Extract[OwnValues[expr], {1, 2}, Hold]  /.
Plus -> Times // ReleaseHold
(* (x + y) (w + z) *)

• Unfortunately I have no control over how any of the expressions are defined. I'll add this to the question Dec 21, 2022 at 11:45
• I added a hack for this case. Dec 21, 2022 at 12:06
• This works! Thanks! Dec 21, 2022 at 12:13
a := x + y
expr := a + b
b := z + w


TL;DR

You can use Block to block definitions of global variables including system variables.

Your example:

Block[{a, b}, expr /. Plus -> Times]


(* (x + y) (w + z) *)

Further explanation and details

To see what is going on here you can use Print or Echo

Block[{a, b}, Print[expr]; expr /. Plus -> Times]


printed output : a+b

So Block is doing it's job of blocking the definitions of a and b. This is only temporary within the block. Once the expr is released into the wild of your notebook a and b regain their definitions.

To illustrate the power of Block more, consider doing the same with system functions:

A user defined function depending on system functions:

m = x |-> Sin[x]*Cos[x];


Say we want to turn m[Pi] to Sin[Pi]+Cos[Pi] rather than Sin[Pi]*Cos[Pi]

m[Pi] /. Times -> Plus


(* 0 *)

because of the Sin[Pi].

m[Pi] /. {Sin -> sin, Cos -> cos} will not work either because m[Pi] is already evaluated by the time Mathematica tries the replacement.

Momentarily blocking the definitions of Sin and Cos so that they do not evaluate :

Block[{Sin, Cos}, m[4] /. Times -> Plus]


(* -1 *)

which is Cos[Pi]

• This one is pretty cool and deserves an upvote, but doesn't work for my particular case, as I don't know what expr is composed of (a and b) Dec 21, 2022 at 18:35
• @BorislavStanimirov Oh so you really did need to check the own values. The question is misleading then why not ask "how to modify the definition of a function written by someone else in a package" Dec 21, 2022 at 18:41

It seems you are overthinking. It is better to use a function:

expr[op_, u_, v_] := op[u, v]


Now we can do

expr[Plus, a, b]
(*a + b*)
expr[Times, x + y, z + w]
(*(x + y) (w + z)*)

• OP mentioned that they have no control over expr, presumably the actual problem is more complicated and expr is a complicated function inside a package that was made by someone else for example. Dec 21, 2022 at 17:12
• @userrandrand If expr is so complicated and OP does not have any control over it, then any of these solutions will fail. It's enough to have a couple of 'Plus' in the code. How would you indicate which Plus should be replaced with Times? To be honest, I cannot even think of a hypothetical situation where something like this would be needed. Dec 21, 2022 at 17:19
• Me neither but OP already mentioned in a comment to the accepted answer that they have no control over expr when an answer modifying expr was used. OP seemed happy with the method that changed the ownvalues of expr. Not sure what the actual context is just noting that a priori OP can not change expr Dec 21, 2022 at 17:21
• @userrandrand If OP is happy, I am perfectly fine :) But sometimes it helps to looks at the problem at different angle. Dec 21, 2022 at 17:23
• True maybe your answer might give a change of perspective. Let's see (:. Dec 21, 2022 at 17:23

another variation. I am using the nice trick for the initial simplify with side relation to work thanks to bmf shown here

ClearAll["Global"]
a := x + y
expr := a + b
b := z + w


And now

Times @@ Simplify[expr, {a == Unevaluated@a0, b == Unevaluated@b0}] /. {a0 ->a, b0 -> b}
`