5
$\begingroup$

Here is an example of my issue:

condition=m>0;
f[m_] = Which[condition == True, 1, condition == False, 2]
f[-10]

returns

Which[(m > 0) == False, 2]

Why? I do not understand. What is even more odd is that flipping order inside "which", reverses where the problem occurs.

condition = m > 0;
f[m_] = Which[condition == False, 2, condition == True, 1];
f[-10]

returns

2

but the function now fails for say $f[10]$.

I know that I can fix the issue just by saying $m>0$ and $m<0$ but the conditions in my real code are much more complicated so I cannot do that. I must be making some syntax error. Thank you.

$\endgroup$
4
  • 5
    $\begingroup$ Lots of misunderstanding here ... Addressing all of them would take a long answer. It's best if you explain what you want to achieve and then someone can provide a solution. First, only use == for writing equations or testing numerical equality. See also ===. Second, don't use condition === True and condition === False. Use condition and Not[condition]. $\endgroup$
    – Szabolcs
    Jan 22, 2022 at 16:48
  • 2
    $\begingroup$ f[m_] := 2 - Boole[m > 0] $\endgroup$
    – Bob Hanlon
    Jan 22, 2022 at 17:22
  • 3
    $\begingroup$ Since Which has the attribute HoldAll, it's best not to have the def. of f depend on external values. E.g. f[m_] := With[{condition = m > 0}, Which[condition, 1, ! condition, 2]] $\endgroup$
    – Michael E2
    Jan 22, 2022 at 17:52
  • $\begingroup$ I've seen condition === False before, and it can make sense if you cannot be sure condition has evaluated to True or False. $\endgroup$
    – Michael E2
    Jan 24, 2022 at 4:29

2 Answers 2

7
$\begingroup$

I would do this as follows

ClearAll[m]
condition[m_] := m > 0;
f[m_] := Which[condition[m], 1, Not[condition[m]], 2]

Mathematica graphics

Your condition == False is not right. And better to use functions for everything.

Answer to comment

If you do not want to use := and want to use immediate assignment, then need to add Evaluate

condition = m > 0;
f[m_] = Which[Evaluate[condition == True], 1, Evaluate[condition == False], 2]

Mathematica graphics

$\endgroup$
7
  • $\begingroup$ Why is condition==False not right? I thought it tells if two things are equal. So if condition is False, they should be identical and hence should return True. No? $\endgroup$
    – 2132123
    Jan 22, 2022 at 16:52
  • $\begingroup$ Also, why use SetDelayed for both definitions? Sorry for so many questions $\endgroup$
    – 2132123
    Jan 22, 2022 at 16:52
  • $\begingroup$ @2132123 added note. The issue is evaluation, since you used immediate assignment. Better to stick to one method. I prefer delayed assignments for functions and to use functions for everything instead of having symbols just all over the place in global context. $\endgroup$
    – Nasser
    Jan 22, 2022 at 17:00
  • $\begingroup$ Thank you very much for that addition. So just to be sure. The issue was that condition was held in unevaluated form? It is not -10>0==True but rather m>0==True? I guess I thought assigning $m$ a value would influence all $m's$ inside the functions definition $\endgroup$
    – 2132123
    Jan 22, 2022 at 17:05
  • 2
    $\begingroup$ @2132123 it has to do with evaluation. As noted above by Michale, Which has HoldAll. It is better as a general rule to use functions with delayed assignments and pass arguments into the function you want to work on these arguments. This will eliminate all these evaluation order issues. If you use immediate assignment for function, then its body is evaluated at the time the definition is made, on whatever variable has values at the moment. Not when the function is called. So it is more safe to use := (delayed) for functions unless there is specific reason not to do so. $\endgroup$
    – Nasser
    Jan 22, 2022 at 18:14
4
$\begingroup$

A better way to define that function is this:

f[m_]:=If[m>0,1,2]

or this:

f[m_]:=1+UnitStep[m]

However, if I was going to do that using Which, I would do this.

f[m_]:=Which[m>0,1,m<=0,2]

To understand the output of the original question consider evaluation of this code.

var=Sin[x];
g[x_]:={2x,3 var};
g[b+5]
(* {2 (5+b),3 Sin[x]} *)

When g[b+5] evaluates, (b+5) is used each place (x) appears on the right side of the definition of g[x_]. However that happens before {2 x, 3 var } evaluates. So the result is {2(b+5),3 var} and then var evaluates to Sin[x] but by then (x) is no longer associated with (b+5).

To develop effective programming habits in Mathematica, follow the style of those who write Mathematica books or learn from examples in the Wolfram documentation. For additional nuances related to the above example read this.

**** Update ****

Details of the evaluation process is in Chapter 7 of this book, this web-page, and this Mathematica documentation.

$\endgroup$
3
  • 1
    $\begingroup$ Very interesting. How do I know in what order Mathematica does thing? Is it in official documentation? $\endgroup$
    – 2132123
    Jan 22, 2022 at 19:18
  • $\begingroup$ @2132123 I updated my answer to include links to the evaluation process. $\endgroup$
    – Ted Ersek
    Jan 22, 2022 at 21:14
  • 1
    $\begingroup$ See Operator Input Forms Table of operator input forms, in order of decreasing precedence. Operators of equal precedence are grouped together. $\endgroup$
    – Bob Hanlon
    Jan 22, 2022 at 21:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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