# Prevent expression from evaluation in function when using ToString

I defined function fhold

Clear[fhold]
SetAttributes[fhold, HoldAll]
fhold[para_List] := ToString[para];


What I want is that when evaluate the following

k0 = 0.4 \[Pi];
fhold[{1, k0}]


I want it to give

"{1,0.4π}"


But it won't, it gives

"{1, 1.25664}"


Using HoldForm will not work either,

fhold[para_List] := ToString[HoldForm@para];


will give

"{1, k0}"


So how to define fhold to get "{1,0.4π}"?

• It is too late. By the time fhold sees k0, k0 has already evaluated to 1.25664. You can't work back from this; the solution is to have e.g. k0 = HoldForm[0.4 \[Pi]]. Then, fhold works as it is. Nov 4, 2015 at 1:48
• I suppose using rational coefficients is out of the question? Nov 4, 2015 at 1:57
• @OleksandrR. The problem is that the function I really works with doing numerical calculation. If I supplied it with HoldForm[k0], calculation won't be done. The reason I want to get string "{1,0.4π}" is that I have lines in the function to DumpSave the result into a file, and I use "{1,0.4π}" in the file name Nov 4, 2015 at 1:59
• @OleksandrR. and also k0 is a key variable, and its value is used in many other place, so I assign the value specifically Nov 4, 2015 at 2:00

You at least have to provide k0 with a delayed definition, otherwise you've fallen at the first hurdle, since the original input will already have been lost. This will give you a fighting chance:

k0 := 0.4 π;


Now, we need to work with the (unevaluated) ownvalues of this symbol, rather than allowing its definition ever to evaluate. Since we don't know what might be contained within the list (symbols or otherwise), we need rules to deal with all possibilities rather than just passing them indiscriminately to OwnValues:

ClearAll[myOwnValues];
SetAttributes[myOwnValues, HoldAll];
myOwnValues[lst_List] := myOwnValues /@ Unevaluated[lst];
myOwnValues[sym_Symbol] := OwnValues[sym];
myOwnValues[_] := {};


Now,

Flatten@myOwnValues[{1, k0}]
(* -> {HoldPattern[k0] :> 0.4 π} *)


which is a reasonable start.

Modifying your fhold to use this is straightforward:

ClearAll[fhold];
SetAttributes[fhold, HoldAll];
fhold[para_List] := ToString[HoldForm[para] /. Flatten@myOwnValues[para]];


And,

fhold[{1, k0}]
(* -> "{1, 0.4 Pi}" *)


as desired.

If you insist on π instead of Pi, you will need to specify ToString[..., StandardForm] rather than the default second argument of OutputForm. Or, remove ToString entirely and just leave HoldForm as the wrapper for this output.