0
$\begingroup$

Ok, so here is example code:

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
If[flag, p, k] = 0;
p

After that I get the message

Set::write: Tag If in If[True,p,k] is Protected.

And p is still 2 instead of 0. How can I make the p equal to 0 in this case?

EDIT: My question is general - how to return the symbol from some function, not only If - and be able to change its value later (for example by Set)

EDIT #2: I know that with associations I can do that easily:

Clear[p, flag, k];
v = <||>;
v[p] = 2;
v[k] = 1;
flag = True;
v[If[flag, p, k]] = 0;
v[p]

I just wish I could the same just on symbols..

$\endgroup$
9
  • $\begingroup$ Your are trying to define a value for the function "If", but "If" is protected. "If" can not be on the left side of an assignment.. Even if it were executed, you would then have "2=0". $\endgroup$ Sep 23, 2020 at 16:23
  • $\begingroup$ I know but how to assign to p properly then ? $\endgroup$
    – Saeki Amae
    Sep 23, 2020 at 16:24
  • $\begingroup$ Or in general, how to return from that if the symbol and then assign value to it? $\endgroup$
    – Saeki Amae
    Sep 23, 2020 at 16:26
  • 4
    $\begingroup$ It is not exactly clear what you want to do. Perhaps: If[flag,p=0,k=0] $\endgroup$ Sep 23, 2020 at 16:28
  • $\begingroup$ So i have to write = 0 twice? There is no option to get just the symbol and then assign? $\endgroup$
    – Saeki Amae
    Sep 23, 2020 at 16:31

3 Answers 3

3
$\begingroup$

At first I wasn’t sure how to realize this, but upon seeing m_goldberg’s example with Set inside of If, it hit me:

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
If[flag, Set[p,#], Set[k,#]]&[0];
p

And this, of course, returns 0 if flag = True and 2 if flag = False.

It might be easier to see it this way:

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
If[flag, p=#, k=#]&[0];
p

which also works like the above. You could streamline this a bit more & wrap it into a function, but I think this answers your question & gives it to you in a form that is loose enough for you to modify to your desires! Nothing fancy, just anonymous functions.

$\endgroup$
2
  • 1
    $\begingroup$ +1 I also had your 2nd example as an afterthought, but when I signed in to update my answer, i was way too late. $\endgroup$
    – m_goldberg
    Sep 24, 2020 at 9:56
  • $\begingroup$ @m_goldberg you could update/expand upon the 1st example you have by having ”=“<>ToString[arg] and make it a function, where arg is 0, for OP’s case? Maybe that’s a bit less concise though... $\endgroup$ Sep 24, 2020 at 11:47
1
$\begingroup$

Here are two methods that are essentially the same.

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
Evaluate[If[flag, p =.; p, k =.; k]] = 0;
p  {* 0 *}

If you want to use a function, maybe this method:

Clear[func, p, flag, k];

func[flag_?BooleanQ, str1_String, str2_String] := If[flag,
  Clear[str1]; ToExpression[str1],
  Clear[str2]; ToExpression[str2]]

p = 2;
k = 1;
flag = True;
Evaluate[func[flag, "p", "k"]] = 0;
p  (* 0 *)

The salient points are (1) the symbol must be cleared or unset and (2) use Evaluate on the left side of the equals sign.

$\endgroup$
1
$\begingroup$

Here is a fairly concise but still silly way to do it.

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
ToExpression[If[flag, "p", "k"] <> "=0"];
p
0

However, I would rather write

Clear[p, flag, k];
p = 2;
k = 1;
flag = True;
If[flag, p = 0, k = 0];
p

and, I believe, so would everybody else. it is the standard practice and is both more concise and efficient then any playing games to limit the code to one written Set expression.

$\endgroup$

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.