11
$\begingroup$

I have the Symbol e with some upvalues and ownvalues:

f[e] = 1;
g[e] = 2;
e = 3;

I would like the evaluator to evaluate the definitions in that order. Currently, I get

f[e] 
(* f[3] *)

I want

f[e] 
(* 1 *)

The evaluator applies the ownvalues before the downvalues, this is documented. I want it to apply the downvalues first, then use the ownvalues. I'm sure there's some clever way of making this happen, I can't imagine this is too uncommon, but perhaps it is. I would prefer a solution that doesn't rely on $Pre, but beggers can't be choosers. The most ideal would be some attribute/thing I can attach to the symbol e itself.

There's a number of related posts on the topic of nonstandard evaluation but I have been unable to glean a solution from them: 40165, 106068, 95087, 40165, 189014, 155480, 19067.

Additionally the documentation doesn't really discuss this as far as I can tell: guide, tutorials.

Edit Ok, I feel like the answers given give me enough to work with on my own. I had thought of trying a conditional ownvalue but didn't know how to implement it. Leonid Shifrin's solution shows how, and confirms my suspicions that it is an inefficient and fragile solution. Nonetheless, I don't think there is too much need to keep it open, and I will accept Leonid's solution and Michael E2's attribute method (which I probably should have thought of myself). Thanks for the help yall.

$\endgroup$
4
  • 2
    $\begingroup$ Well, it works if you set SetAttributes[f, HoldAll] etc., but it's probably not what you want. $\endgroup$
    – Michael E2
    Commented Feb 3, 2020 at 4:01
  • $\begingroup$ Yes, I am trying to do this without modifying f or g, but that is not actually the end of the world if I have to. Thanks, I didn't know that would work. I guess I haven't studied the function attributes documentation enough :) $\endgroup$ Commented Feb 3, 2020 at 4:06
  • 1
    $\begingroup$ I'd not set OwnValues and do whatever /. e->3. It is up to you but if need to change the evaluation process then maybe something else should be changed. $\endgroup$
    – Kuba
    Commented Feb 3, 2020 at 7:18
  • $\begingroup$ @TannerLegvold I've edited the post to change "upvalues" to "downvalues" where appropriate, since what you are defining seem to be the latter. Please feel free to revert the edit if I misunderstood you $\endgroup$
    – Lukas Lang
    Commented Feb 3, 2020 at 8:52

3 Answers 3

13
$\begingroup$

While I agree with the opinion that the need for serious changes in evaluation sequence in most cases means that the approach isn't best, here is one possible way of achieving what you ask - use conditional OwnValue:

f[e] = 1;
g[e] = 2;
e /; ! MemberQ[Stack[_], HoldForm[(f | g)[e]]] := 3;

Now

e

(* 3 *)

f[e]

(* 1 *)

g[e]

(* 2 *)

This solution has a number of issues however, it is rather fragile (uses entire stack, so is non-local) and also performance can be bad. So I would still try to reconsider the approach.

$\endgroup$
9
$\begingroup$

I am not sure this might be useful, but if I want to evalutate f[e] before e, then I simply would not evaluate e

f[e] = 1;
g[e] = 2;
e = 3;

f[e//Unevaluated]

1

g[e//Unevaluated]

2

$\endgroup$
7
$\begingroup$

Alternatively:

ClearAll[f, e]
f[e] = {1, e};
e = 3;

f[e]

f[3]

Block[{e}, f[e]]

{1, 3}

And if there are other types of values associated with e like:

ClearAll[e, f];
e /: f[e] := {100, e};
e = 5;

Then:

Internal`InheritedBlock[ {e},
 e =.;
 f[e]
]

{100, 5}

$\endgroup$

Your Answer

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

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