How to Block Symbols without evaluating them?

∥☆過路亽.° 提交于 2019-11-30 02:06:49

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]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!