11
$\begingroup$

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?

$\endgroup$
2
  • $\begingroup$ 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.) $\endgroup$
    – Szabolcs
    Jul 21, 2012 at 10:03
  • $\begingroup$ @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? $\endgroup$
    – Mr.Wizard
    Jul 21, 2012 at 10:05

3 Answers 3

9
$\begingroup$

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]

$\endgroup$
1
  • $\begingroup$ Competing UpValues! Brilliant. $\endgroup$
    – Mr.Wizard
    Jul 21, 2012 at 22:36
6
$\begingroup$

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:

Internal`InheritedBlock[
 {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.

$\endgroup$
7
  • 1
    $\begingroup$ Intersting one... $\endgroup$
    – Rojo
    Jul 21, 2012 at 12:08
  • $\begingroup$ @Rojo I'm still reading the other solutions. $\endgroup$
    – Szabolcs
    Jul 21, 2012 at 12:11
  • 2
    $\begingroup$ +1, clever. If desired, we can avoid using Internal`InheritedBlock 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}]. $\endgroup$
    – WReach
    Jul 21, 2012 at 17:57
  • $\begingroup$ @WReach & Szabolcs I don't understand how this works (both methods). Please enlighten me! $\endgroup$
    – Mr.Wizard
    Jul 21, 2012 at 22:39
  • $\begingroup$ @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). $\endgroup$
    – Szabolcs
    Jul 21, 2012 at 22:43
5
$\begingroup$

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]
$\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.