Disclaimer: While my response provides a solution to the problem as expressed, I do not recommend it for regular use. I offer it up because it may be of some academic interest.
From time-to-time, usually in a debugging context, I have looked longingly at Lisp's MACROEXPAND-1
and wished for a Mathematica function which applies only one level of evaluation to its argument(s). Let's call this mythical function EvaluateOnce
. It would find the transformation rule applicable to the expression and apply only that rule, something like this:
In[19]:= fact[0] = 1; fact[x_] := x * fact[x - 1]
EvaluateOnce[fact[5]]
Out[19]= Hold[5 fact[5-1]]
In[20]:= f1 := Print["f1 is evaluated!"];
EvaluateOnce[Symbol["f1"]]
Out[20]= Hold[f1]
It would work on multiple expressions as well:
In[21]:= EvaluateOnce[1 + 2 * 3, Sqrt @ Sin @ Pi]
Out[22]= Hold[1+6, Sqrt[0]]
The current question could benefit from such a capability for then the solution could be expressed as:
EvaluateOnce @@ Symbol /@ Hold @@ list /.
Hold[args__] :> Block[{args}, f1 // ToString]
Alas, there are a number of technical obstacles to writing such a function -- not least of which is a certain amount of fuzziness about what exactly constitutes a "single level of evaluation" in Mathematica. But fools rush in where angels fear to tread, so I offer this hack:
ClearAll@EvaluateOnce
SetAttributes[EvaluateOnce, HoldAllComplete]
EvaluateOnce[exprs:PatternSequence[_, __]] :=
Replace[Hold @@ Evaluate /@ EvaluateOnce /@ Hold[exprs], Hold[e_] :> e, 1]
EvaluateOnce[expr_] :=
Module[{depth = 0, length = 1+Length@Unevaluated@expr, tag, enter, exit}
, SetAttributes[exit, HoldAllComplete]
; enter[in_]:= If[1 === depth && 0 === length, Throw[in, tag], ++depth]
; exit[in_, out_] := (If[2 === depth, length--]; depth--)
; Hold @@ Catch[With[{r = TraceScan[enter, expr, _, exit]}, Hold[r]], tag]
]
This function comes without a warranty :) It uses TraceScan
and some heuristics to guess when a "single level of evaluation" is complete and then uses Throw
and Catch
to terminate the evaluation sequence early.
The heuristics appear to work satisfactorily for function definitions whose "first level of evaluation" stays within the bounds of standard evaluation. It also fails miserably for those that don't. I'm also certain that it will get confused with the application of some evaluation attributes.
Notwithstanding these faults, I still find this function handy when trying to debug or even just understand functions with lots of standard pattern-matching definitions.