Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Background:

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

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 ?

share|improve this question
add comment

2 Answers 2

up vote 7 down vote accepted

You need to use HoldForm instead of Hold.

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

With this:

f[ape]
(* "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 *)
share|improve this answer
    
Hmm, 4 seconds difference –  Heike May 5 '12 at 17:41
    
Oooh. That's the closest I've been involved in! :) –  rm -rf May 5 '12 at 17:47
    
Any reason for name_?StringQ rather than name_String? –  Mr.Wizard May 5 '12 at 18:21
    
@Mr.Wizard That's what the OP used for whatever reason and I stuck with it –  rm -rf May 5 '12 at 18:28
5  
@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... –  Albert Retey May 5 '12 at 18:34
show 2 more comments

You could use HoldForm instead of Hold, for example

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

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

Edit

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};

foo[bar]

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

foo[bar + ape]

(* ==> {{3, 4, 5}, False} *)
share|improve this answer
    
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 –  ndroock1 May 5 '12 at 17:48
    
@ndroock1 I've updated my answer –  Heike May 5 '12 at 18:04
2  
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... –  Albert Retey May 5 '12 at 18:47
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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