In Mathematica:
I would like to pass a variable number of arguments to a function.
I would like to print the name of each argument. The problem is that SymbolName evaluates its input. For a given variable, you can get around this:
a=18;
SymbolName[Unevaluated[a]]
works. But that won't work if the variable is in a list. For example:
printname[x__]:=Print[Table[SymbolName[Unevaluated[{x}[[i]]]],{i,1,Length[{x}]}]];
printname[a,b,c]
will not work. Any suggestions?
Thanks in advance.
Mathematica tries to evaluate the argument of Unevaluated[]
when you call it. So {x}[[i]]
gets converted into {18, b, c}[[i]]
which you didn't want and then the iteration over i
doesn't work anymore because Unevaluated[]
doesn't let the Table
access the iterator.
So, to really solve the issue you should disable Mathematica's evaluation completely for the functions that you want to pass the symbols through.
In[1]:= SetAttributes[SymbolName, HoldAll];
SetAttributes[Map, HoldAll];
After this you can just do
In[2]:= a=18; SymbolName @@@ Unevaluated /@ {a, b, c}
Out[2]:= {a, b, c}
where @@@
and /@
are shorthand for Apply[]
and Map[]
.
Setting Hold[]
or similar attributes in Mathematica's built in functions can lead to trouble. See this question and answer in the Mathematica stackexchange for more information.
Specifically, to make a function that takes an arbitrary number of arguments would be
sym = SymbolName @@@ Unevaluated /@ {##} &
But the List[]
function that takes the sequence of arguments ##
for the function &
will again evaluate a
and turning HoldAll
on for List[]
is not OK.
Thus the easiest way to do this is to define a function with HoldAll
that just passes the args into a Block[]
as the list of local variables. This makes a creates an isolated context where the variables do not evaluate to anything.
In[1]:= SetAttributes[f, HoldFirst];
In[2]:= f[seq__] := Block[{seq}, Print[SymbolName /@ {seq}]];
In[3]:= a=18; f[a, b, c]
Out[3]:= {a, b, c}