bar := {1, 1, 1};
  foo[var_] := {Hold[var], 2 var}
  SetAttributes[foo, HoldAll]

Result, as expected:

  {Hold[bar], {2, 2, 2}}

What I then do ( which is clearly not correct, but I don't know another way ) is that I ToString the first element of the list, i.e. Hold[bar] and then extract the substring "bar" out of it.

What I want is just this:

  f[data_?VectorQ] := f[data, name_of_data]
  f[data_?VectorQ, name_?StringQ] := "Save data as name" ...

So for example:

   ape = {1,2,3};
   bear= {2,3,4};
   f[ape] translates to f[{1,2,3"}, "ape"]
   f[bear, "bird"] translates to f[{2,3,4}, "bird"]
   f[ape+bear] translates to Null or False.

Question: How do I access the name of a list in a function ?


You need to use HoldForm instead of Hold.

SetAttributes[f, HoldAll]
f[data_?VectorQ] := f[data, ToString@HoldForm@data]
f[data_?VectorQ, name_?StringQ] := "Save data as " <> name

With this:

(* "Save data as ape" *)

f[ape, "bird"]
(* "Save data as bird" *)

To get Null or False for f[ape+bear], you can use StringFreeQ[name, "+"] to see if the input is of that form. Similarly, "{" for list arguments (no need to check for "}"). So the second definition for f above would be:

f[data_?VectorQ, name_?StringQ] := 
    If[StringFreeQ[name, "+" | "{"], "Save data as " <> name, False]

f[{1, 2, 3}]
(* False *)

f[ape + bear]
(* False *)
  • $\begingroup$ Hmm, 4 seconds difference $\endgroup$ – Heike May 5 '12 at 17:41
  • $\begingroup$ Oooh. That's the closest I've been involved in! :) $\endgroup$ – rm -rf May 5 '12 at 17:47
  • $\begingroup$ Any reason for name_?StringQ rather than name_String? $\endgroup$ – Mr.Wizard May 5 '12 at 18:21
  • $\begingroup$ @Mr.Wizard That's what the OP used for whatever reason and I stuck with it $\endgroup$ – rm -rf May 5 '12 at 18:28
  • 5
    $\begingroup$ @R.M.: I think you need _?StringQ since _String would not work due to the HoldAll attribute. You could alternatively wrap an Evaluate around the second argument in the call to f which would probably a good idea anyway... $\endgroup$ – Albert Retey May 5 '12 at 18:34

You could use HoldForm instead of Hold, for example

bar := {1, 1, 1};
foo[var_] := {ToString@HoldForm[var], var}
SetAttributes[foo, HoldAll]

(* output: {"bar", {1, 1, 1}} *)


To distinguish between proper variable names and something like ape + bear you could do something like

foo[var_] := {var, Quiet@Check[SymbolName[Unevaluated[var]], False]}
SetAttributes[foo, HoldAll]

bar := {1, 1, 1};
ape = {2, 3, 4};


(* ==> {{1, 1, 1}, "bar"} *)

foo[bar + ape]

(* ==> {{3, 4, 5}, False} *)
  • $\begingroup$ Is there a smart way to check that only f[varname] is OK and not f[{1,2,3}] or f[var1+var2+var3] etc.? they all pass VectorQ $\endgroup$ – nilo de roock May 5 '12 at 17:48
  • $\begingroup$ @ndroock1 I've updated my answer $\endgroup$ – Heike May 5 '12 at 18:04
  • 2
    $\begingroup$ As for the check whether the argument is a symbol you could just use foo[var_Symbol]:=... or even combine it with _?VectorQ as this: _Symbol?VectorQ. It might come as a surprise that this works but _Symbol will check the Head of the unevaluated argument due to the HoldAll attribute while the VectorQ will see the evaluated argument. And yes, Leonid would for sure consider the _?VectorQ part to be an evaluation leak. For this particular use case I would consider that no problem though... $\endgroup$ – Albert Retey May 5 '12 at 18:47

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.