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