1
$\begingroup$

Consider the following function:

f[arg_] := Print[Unevaluated[arg]];
Attributes[f] = HoldAll;

The purpose of the function is to print the arguments unevaluated. In particular, what's important to me is that a symbol that already has a value will be printed as the symbol and not the value. For example:

x = 1;
f[x];

The output is x as desired. But now I want to have the same behaviour with multiple arguments, either as a List or a BlankSequence. Here are my attempts:

With a List:

fList[args_] := Print[Unevaluated /@ args]; 
Attributes[fList] = HoldAll;
x = 1;
y = 1;
fList[{x, y}]

With a BlankSequence:

fBS[args__] := Print[Unevaluated /@ {args}];
Attributes[fBS] = HoldAll;
x = 1;
y = 1;
fBS[x, y]

In both cases the expected output is {x, y}, but what I actually get is {Unevaluated[1], Unevaluated[1]}! It seems that the HoldAll attribute doesn't actually do anything in these cases... Is there any way to solve this issue?

Thanks.

Edit in response to comments:

I understand that f[{x,y}] with the original f will work, if all I want to do is print the arguments. But what I wrote here is just a simple toy example. The actual function I want to use in my program does other things with the arguments, and needs to be able to access each argument's symbol individually.

Consider this (also toy) example instead:

g[arg_] := ToCharacterCode[ToString[Unevaluated[arg]]];
Attributes[g] = HoldAll;
x = 1;
y = 1;

The output of g[x] will be {120}. But the output of g[{x, y}] will be {123, 120, 44, 32, 121, 125} which is of course not what I want. I want a function that will return {120, 121}, i.e. the character codes of the letters x and y.

If I try for example:

gList[args_] := ToCharacterCode[ToString /@ Unevaluated[args]];
Attributes[gList] = HoldAll;
gList[{x, y}]

I get {{49}, {49}} which are the character codes of 1, instead of {{120}, {121}} which is what I want. Is there any function that will return the desired result?

$\endgroup$
9
  • $\begingroup$ For the case of fList, just use your f (f[{x, y}]). For the case of dBS, use fBS[args__] := f[{args}]. There is no need to map on individual arguments, if you anyway want them all to print unevaluated values. $\endgroup$ Aug 2 at 17:12
  • 2
    $\begingroup$ The issue is that Map[Unevaluated, {args}] evaluates {args}. $\endgroup$
    – Carl Woll
    Aug 2 at 17:13
  • $\begingroup$ Thanks! Please see my edit for a clarification. $\endgroup$
    – CMB
    Aug 2 at 18:42
  • $\begingroup$ In your updated gList example, ToString is not a Hold function and evaluates its argument. You could fix this by using Function[Null, ToString[Unevaluated[#]], HoldAll] or by defining a new HoldFirst toString function that doesn't evaluate its argument. $\endgroup$
    – Carl Woll
    Aug 2 at 18:50
  • $\begingroup$ Attributes[g] = {HoldAll, Listable};? $\endgroup$
    – Michael E2
    Aug 2 at 18:51
2
$\begingroup$

Your original f already handles the List case:

f[arg_] := Print[Unevaluated[arg]];
Attributes[f] = HoldAll;
x = 1;
y = 1;
f[{x, y}]

For the multi-argument version, you need to hold the arguments before passing them to Map. For example, using HoldComplete:

fBS[args__] := Print @@ Unevaluated /@ HoldComplete[args];
Attributes[fBS] = HoldAll;
x = 1;
y = 1;
fBS[x, y]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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