5
$\begingroup$

I tried this:

Plo[fun__] := SymbolName @ Part[List @@@ Unevaluated @@ {Hold[fun]}, {1}, 2]
SetAttributes[Plo, HoldAll]

On Plo[aaa,bbb] it writes

SymbolName::sym: Argument Unevaluated[bbb] at position 1 is expected to be a symbol.

When I write manually the returned value

SymbolName[Unevaluated[bbb]]

it works..

$\endgroup$
2
  • 1
    $\begingroup$ Try with Plo[fun__] := With[{tmp = Part[List @@@ Unevaluated @@ {Hold[fun]}, {1}, 2]}, SymbolName[tmp]]. $\endgroup$ Commented Jul 29, 2022 at 23:19
  • $\begingroup$ Thanks, works. Is it because the HoldAll applied inside? But I also tried to have the symbolname outside the function . $\endgroup$ Commented Jul 29, 2022 at 23:24

3 Answers 3

6
$\begingroup$

The following does what you want:

SetAttributes[Plo,HoldAll] 
Plo[fun__]:=SymbolName@@{Unevaluated@@Hold[fun][[{2}]]}

Besides some cleanup of your function, the key fix is the use of Apply to apply SymbolName to the Unevaluated[…] expression. To understand the difference, it is important to realize the following: When the evaluator is evaluating an expression of the form head[arg1,arg2,…],head is evaluated first. After this, the arguments are considered one after the other: If evaluation is prevented by a Hold* attribute, nothing is done. Otherwise, if the argument is wrapped in Unevaluated, the wrapper is removed, and nothing more is done. Otherwise, the argument is evaluated normally. The key here is that only Unevaluated wrappers literally present when first starting this process have the intended effect. Once the evaluation of an argument has begun, it can't be "stopped" midway through. If an Unevaluated wrapper appears as part of the evaluation of the argument, it is simply ignored. This is exactly what happens in your code. The code above circumvents this by making sure the Unevaluated wrapper is literally present before the expression SymbolName[…] is constructed.

$\endgroup$
2
  • $\begingroup$ @DanielHuber Unless I'm missing something, that's not necessary? Pattern has attribute HoldFirst, so fun having a value doesn't cause any problems (at least in my testing) $\endgroup$
    – Lukas Lang
    Commented Jul 30, 2022 at 8:23
  • $\begingroup$ Sorry, you are right. $\endgroup$ Commented Jul 30, 2022 at 8:48
2
$\begingroup$

I'm not sure what the "nth" argument is supposed to be, since n does not appear in the OP, just 2. So here's a way to get the name of a Symbol argument for a fixed n, as in the OP:

plo // ClearAll;
SetAttributes[plo, HoldAll];
With[{nMinusOne = 2 - 1},
 plo[Repeated[_, {nMinusOne, nMinusOne}], arg_, ___] := 
   SymbolName@Unevaluated@arg;
 ]

Block[{bb = 3}, plo[aa, bb, cc, dd]]

(*  "bb"  *)

Another way; this time with an adjustable n depending on a global variable $myN (one could make it an argument to plo[n, fun] but the need is unclear):

plo // ClearAll;
SetAttributes[plo, HoldAll];
$myN = 2;
plo[fun__] := With[{n = $myN},
   Function[, SymbolName@Unevaluated@Slot[n], HoldAll][fun]
   ];

Block[{bb = 3, cc = 7, $myN = 3}, plo[aa, bb, cc, dd]]

(*  "cc"  *)

After seeing the OP's application of this problem, I thought of this way to get the output of the OP's answer without having to use Part:

getArgs // ClearAll;
getArgs // Attributes = {HoldAll};
getArgs[fun__] := AssociationThread[
   List @@ SymbolName /@ Unevaluated /@ Hold[fun] -> {fun}];

Block[{bb = 3}, getArgs[aa, bb, cc, dd]]

(*  <|"aa" -> aa, "bb" -> 3, "cc" -> cc, "dd" -> dd|>  *)

(ToString[#, InputForm] &) might be a better transformation of the arguments to strings than SymbolName (for both getArgs[] and plo[]). It's rare that the arguments in my function calls are all symbols. Also getArgs[f_[fun___]] :=... seems more likely to be useful.

$\endgroup$
1
$\begingroup$

Based on the answer in the comments, I can create Association that associates arg names to args. Could be useful. (Keys@GetArgs[...][[n]] is the nth arg)

CreateAssoication[z_] := Association[ #[[1]] -> #[[2]] & /@ z];
GetArgs[fun__] := 
  CreateAssoication@
   Table[With[{tmp = 
       Part[List @@@ Unevaluated @@ {Hold[fun]}, {1}, 
        k]}, {SymbolName[tmp], Evaluate[tmp]}], {k, 1, 
     Length[Hold@fun]}];
SetAttributes[GetArgs, HoldAll];
$\endgroup$
2
  • 3
    $\begingroup$ Did you forget SetAttributes[getArgs, HoldAll];? $\endgroup$
    – Michael E2
    Commented Jul 29, 2022 at 23:57
  • $\begingroup$ yes, indeed , I forgot $\endgroup$ Commented Jul 30, 2022 at 20:00

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.