假设我有一个Symbol
s名称列表:
f1 := Print["f1 is evaluated!"];
list = {"f1", "f2"};
Block
这些Symbol
的显而易见的方法可以评估它们:
In[19]:= With[{list=Symbol/@list},Block[list,f1//ToString]]
During evaluation of In[19]:= f1 is evaluated!
During evaluation of In[19]:= f1 is evaluated!
Out[19]= Null
但是如果没有评估,我们可以Block
毫无问题地进行评估:
In[20]:= Block[{f1, f2}, f1 // ToString]
Out[20]= "f1"
是否可以在不评估Block
的情况下将此列表注入Symbol
范围?
答案 0 :(得分:9)
免责声明:虽然我的回复提供了所表达问题的解决方案,但我不建议将其用于常规用途。我提供它是因为它可能具有一定的学术兴趣。
有时,通常在调试环境中,我一直渴望看到Lisp的MACROEXPAND-1
,并希望Mathematica函数只对其参数应用一级评估。我们称之为神话函数EvaluateOnce
。它会找到适用于表达式的转换规则,并仅应用该规则,如下所示:
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]
它也适用于多个表达式:
In[21]:= EvaluateOnce[1 + 2 * 3, Sqrt @ Sin @ Pi]
Out[22]= Hold[1+6, Sqrt[0]]
当前的问题可以从这种能力中受益,然后解决方案可以表示为:
EvaluateOnce @@ Symbol /@ Hold @@ list /.
Hold[args__] :> Block[{args}, f1 // ToString]
唉,编写这样一个函数存在许多技术障碍 - 尤其是Mathematica中究竟构成“单一评估”的一定程度的模糊性。但是傻瓜在天使们害怕踩到的地方匆匆忙忙,所以我提供了 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]
]
此功能没有保修:)它使用TraceScan
和一些启发式方法来猜测“单一评估级别”何时完成,然后使用Throw
和Catch
来终止评估序列早期。
对于“第一级评估”保持在标准评估范围内的函数定义,启发式算法似乎令人满意。对于那些不这样做的人来说,它也会悲惨地失败。我也确定它会与某些评估属性的应用混淆。
尽管存在这些错误,但在尝试调试甚至只是理解具有大量标准模式匹配定义的函数时,我仍然觉得这个函数很方便。
答案 1 :(得分:8)
这是另一种技术:
SetAttributes[blockAlt,HoldRest];
blockAlt[s : {__String}, body_] :=
Replace[Join @@ ToHeldExpression[s], Hold[x__] :> Block[{x}, body]]
由于规则具有破坏性(他们不尊重其他范围构造,包括他们自己),我们在这里保存纯函数
修改强>
另一种选择(甚至更短):
SetAttributes[blockAlt1, HoldRest];
blockAlt1[s : {__String}, body_] :=
Block @@ Append[ToHeldExpression@ToString[s], Unevaluated[body]]
答案 2 :(得分:6)
您可以尝试使用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
答案 3 :(得分:6)
你可以考虑这个结构:
SetAttributes[block, HoldRest]
block[s : {__String}, body_] :=
Function[, Block[{##}, body], HoldAll] @@
Join @@ MakeExpression /@ s
第二次尝试较短版本的狮子座第二个功能:
block =
Function[, Block @@ ToHeldExpression@ToString@#~Join~Hold@#2, HoldRest]