Suppose I have a list of names of Symbol
s:
f1 := Print["f1 is evaluated!"];
list = {"f1", "f2"};
The obvious way to Block
these Symbol
s leads to evaluation of them:
In[19]:= With[{list=Symbol/@list},Block[list,f1//ToString]]
During evalua开发者_StackOverflow社区tion of In[19]:= f1 is evaluated!
During evaluation of In[19]:= f1 is evaluated!
Out[19]= Null
But without evaluation we could Block
them without any problem:
In[20]:= Block[{f1, f2}, f1 // ToString]
Out[20]= "f1"
Is it possible to inject this list into the Block
scope without evaluating the Symbol
s?
Here is yet another technique to do this:
SetAttributes[blockAlt,HoldRest];
blockAlt[s : {__String}, body_] :=
Replace[Join @@ ToHeldExpression[s], Hold[x__] :> Block[{x}, body]]
We save here on pure functions, due to the disruptive nature of rules (they don't respect other scoping constructs, including themselves)
EDIT
Yet another alternative (even shorter):
SetAttributes[blockAlt1, HoldRest];
blockAlt1[s : {__String}, body_] :=
Block @@ Append[ToHeldExpression@ToString[s], Unevaluated[body]]
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.
You could try to use ToExpression
:
In[9]:= list = {"f1", "f2"};
In[19]:= f1 = 25;
In[20]:= ToExpression[
StringJoin["{", Riffle[list, ","], "}"], InputForm,
Function[vars, Block[vars, f1], HoldAll]]
Out[20]= 25
You may consider this construct:
SetAttributes[block, HoldRest]
block[s : {__String}, body_] :=
Function[, Block[{##}, body], HoldAll] @@
Join @@ MakeExpression /@ s
Second attempt at a shorter version of Leonid's second function:
block =
Function[, Block @@ ToHeldExpression@ToString@#~Join~Hold@#2, HoldRest]
精彩评论