# How can I hold UpValues but evaluate other expressions?

Consider these definitions:

own = "OwnValue";
down[_] = "DownValue";
sub[_][_] = "SubValue";
N[n] = 3.14;
_[___, up, ___] ^= "UpValue";


The attribute HoldAllComplete holds an UpValue but it also holds the other Values as well.

Without advance knowledge of the symbol up how can I evaluate everything but the UpValue?

Set and related functions appear to have this evaluation property internally:

f[own, down[1], sub[1][2], N[n], up] = 1;

Definition[f]

f["OwnValue", "DownValue", "SubValue", 3.14, up] = 1


The first idea that comes to mind is to test if a symbol has an UpValue and skip evaluation if it does, but this proves problematic. First, a symbol can have both an OwnValue and an UpValue, and the OwnValue should be used if possible:

x[up3] ^= 2;
up3 = 1;

f[up3]

f[1] (* desired output *)


Second, testing for an UpValue can be difficult:

_[___, up4, ___] ^= {};

UpValues[up4] === UpValues[Plus]


True

To clarify, it is not my intent to return f[. . ., up] as output, which would require Defer or similar. Rather I would like to handle the expression f[. . ., up] as an argument like Set does, or define a function f[args___] := . . . (with attribute HoldAllComplete) that returns e.g. {"OwnValue", "DownValue", "SubValue", 3.14, HoldComplete[up]}

How can this be achieved?

-
When you write f[up]=1, up appears at the second level. This is the reason why the UpValue does not evaluate. Consider x=up (which is Set[x,up])---this evaluates to "UpValue" right away. Now try SetAttributes[fun, HoldAll] and fun[p[up]]---this one does not evaluate because UpValues are evaluated only in the first level of held heads (just like Unevaluated, Sequence, etc.) – Szabolcs Jul 21 '12 at 10:03
@Szabolcs believe it or not I know this. :^) I guess I didn't formulate my question all that well. Would you join me in Chat to work it out? – Mr.Wizard Jul 21 '12 at 10:05

Does this work as you want to?

SetAttributes[f, HoldAllComplete];
{first, rest___} ^:= HoldComplete[rest]
f[args___] := {first, args}

f[own, down[1], sub[1][2], N[n], up]


HoldComplete["OwnValue", "DownValue", "SubValue", 3.14, up]

-
Competing UpValues! Brilliant. – Mr.Wizard Jul 21 '12 at 22:36

If I understand it correctly, the gist of your question is going from

HoldComplete[x, y, z, up]


to

HoldComplete[1, y^2, z, up]


assuming the following definitions:

_[___, up, ___] ^= "UpValueEvaluated"
x = 1
f[x_] := x^2


That is, evaluate everything inside the HoldComplete except the UpValue. I managed to do this using the following construction:

InternalInheritedBlock[
{RuleCondition},
Attributes[RuleCondition] = {HoldAllComplete};
Replace[HoldComplete[x, f[y], z, up], e_ :> RuleCondition[e], {1}]
]


The undocumented RuleCondition is explained here. This construction should be able to emulate the behaviour of Set.

-
Intersting one... – Rojo Jul 21 '12 at 12:08
@Rojo I'm still reading the other solutions. – Szabolcs Jul 21 '12 at 12:11
+1, clever. If desired, we can avoid using InternalInheritedBlock by means of a helper identity function: SetAttributes[hci, HoldAllComplete]; hci[x_] := x. Then we can write: Replace[HoldComplete[x, f[y], z, up], e_ :> RuleCondition @ hci @ e, {1}]. – WReach Jul 21 '12 at 17:57
@WReach & Szabolcs I don't understand how this works (both methods). Please enlighten me! – Mr.Wizard Jul 21 '12 at 22:39
@Mr.Wizard Here's the key: stackoverflow.com/questions/6633236/… It's a way to evaluate any subexpression inside a held expression. I take all elements of the HoldComplete and evaluate them one-by-one. I need to take care on the way not to end up with something[up] where something doesn't have HoldAllComplete (this way the challenge). – Szabolcs Jul 21 '12 at 22:43

To answer my own question and further illustrate the kind of operation I am describing, here is a method using Set itself:

SetAttributes[f, HoldAllComplete]

f[args___] :=
Module[{h},
h[args] = 1;
Level[DownValues@h, {4}, HoldComplete]
]

f[own, down[1], sub[1][2], N[n], up]

HoldComplete["OwnValue", "DownValue", "SubValue", 3.14, up]

-