Evaluation process in Mathematica can be tricky at the beginning; I suggest reading the tutorial on the Evaluation of Expressions.
The problem you are facing is that both With and If hold their arguments (With is HoldAll, and If is HoldRest). In order to circumvent this, you can wrap the argument with Evaluate.
Let's begin with simpler examples:
cond = a > 0;
With[{a = 1}, cond]
(* a > 0 *)
Why did With not change the value of a? Because, roughly speaking, With replaces only symbols it can lexically explicitly "see"! But it only sees cond, because the evaluation of cond to a > 0 is postponed due to HoldAll. If you cirvument this, cond is evaluated before With does its magic:
With[{a = 1}, Evaluate[cond]]
(* True *)
You can more closely inspect all of this by using Trace.
With[{a = 1}, cond] // Trace
(* {With[{a=1}, cond], cond, a>0} *)
With[{a = 1}, Evaluate[cond]] // Trace
(* {{cond, a>0}, With[{a=1},a>0], 1>0, True} *)
See the difference?
Now to adding If:
int = a x;
With[{a = 1}, If[cond, int]]
(* If[a>0,int] )
With[{a = 1}, Evaluate[If[cond, int]]]
( a x *)
The first output is expected: With didn't see any a to be replaced, so the output is an undecided If. But what's with the second output? Look at the Trace:
With[{a = 1}, Evaluate[If[cond, int]]] // Trace
(* {{{cond,a>0},If[a>0,int]},With[{a=1},If[a>0,int]],If[1>0,int],
{1>0,True},If[True,int],int,a x} *)
Because If holds its arguments (except the first one), they get evaluated only after With has done the replacement! So you have to now also circumvent this holding inside If with another Evaluate:
With[{a = 1}, Evaluate[If[cond, Evaluate[int]]]]
(* x *)
Now let's add Prints:
With[{a = 1},
Evaluate[
If[cond,
Evaluate[Print["1st"]; int],
Evaluate[Print["2nd"]; int]
]]]
(* 1st *)
(* 2nd *)
(* x *)
Whoops? Why did this happen? Well, this is exactly the reason why If holds its arguments! You do not want to evaluate both branches before you now which one is the correct one! However, by using Evaluate, we evaluated both of them, so both Prints occurred. What can you do now? Well, many different options:
- Ugly nested
Withs
With[{a = 1}, Evaluate[With[{int = int}, If[cond, Print["1st"]; int, Print["2nd"]; int]]]]
(* 1st *)
(* x *)
- or more elegantly, define
int and cond as functions
Clear[cond, int];
cond[a_] := a > 0;
int[a_] := ax;
With[{a = 1}, If[cond[a], Print["1st"]; int[a], Print["2nd"]; int[a]]]
(* 1st )
( x *)
Trace! (2) You have to wrap the whole thing insideWithwithEvaluate(Evaluate[e1; e2]), not each separate statement (Evaluate@e1; Evaluate@e2;) to overcome the fact thatWithisHoldAll. Otherwise,Evaluatedoesn't have the desired effect. – Domen Mar 15 '24 at 11:11Printand that it should affect the evaluation process. – three777 Mar 15 '24 at 11:13;is also a functionCompoundExpression. WhenEvaluateis inside theCompoundExpression, it no longer breaks throughHoldRestattribute ofIf. – xzczd Mar 15 '24 at 11:17WithandIf! That is why you need to escape both of them by two separateEvaluates:With[{a = 1}, Evaluate[If[cond, Evaluate[Print["First possibility:"]; Integrate[int, {x, 0, a}]], Evaluate[Print["Second possibility:"]; Integrate[int, {x, -a, 0}]]]]]– Domen Mar 15 '24 at 11:18Tracefor your cases! :) It will help you understand better what is going on. – Domen Mar 15 '24 at 11:19"First possibility:"and"Second possibility:". Which is nonsense. – three777 Mar 15 '24 at 11:32Evaluatein last case, I'm just explaining why your last trial fails. – xzczd Mar 15 '24 at 11:47Printplays a substantial role here not justWithandIf. – azerbajdzan Mar 15 '24 at 11:56