Pil*_*lsy 13 error-handling wolfram-mathematica
是好还是坏,Mathematica提供了丰富的结构,让你做控制的非本地传输,其中Return,Catch/ Throw,Abort和Goto.但是,这些非本地控制转移通常与编写需要确保清理代码(如关闭流)运行的强大程序相冲突.许多语言提供了确保清理代码在各种情况下运行的方法; Java有它的finally块,C++有析构函数,Common Lisp有UNWIND-PROTECT,等等.
在Mathematica,我不知道如何完成同样的事情.我有一个部分解决方案,如下所示:
Attributes[CleanUp] = {HoldAll};
CleanUp[body_, form_] :=
Module[{return, aborted = False},
Catch[
CheckAbort[
return = body,
aborted = True];
form;
If[aborted,
Abort[],
return],
_, (form; Throw[##]) &]];
Run Code Online (Sandbox Code Playgroud)
这肯定不会赢得任何选美比赛,但它也只能处理Abort和Throw.特别是,它存在失败Return; 我想如果你Goto在Mathematica中使用这种非本地控制你应得的.
我没有看到这方面的好方法.CheckReturn例如,没有,当你接受它时,它Return具有非常模糊的语义.有缺点我不知道吗?
编辑:问题Return及其定义中的模糊性与其与条件的相互作用有关(在某种程度上它不是Mathematica中的"控制结构").一个例子,使用我的CleanUp表单:
CleanUp[
If[2 == 2,
If[3 == 3,
Return["foo"]]];
Print["bar"],
Print["cleanup"]]
Run Code Online (Sandbox Code Playgroud)
这将返回"foo"而不打印"cleanup".同样,
CleanUp[
baz /.
{bar :> Return["wongle"],
baz :> Return["bongle"]},
Print["cleanup"]]
Run Code Online (Sandbox Code Playgroud)
将返回"bongle"而不打印清理.我没有看到这种方法,没有繁琐,容易出错,可能不可能的代码行走或以某种方式在本地重新定义Return使用Block,这是非常hacky并且实际上似乎没有工作(虽然尝试它是一个很好的方式来完全楔入内核!)
很好的问题,但我不同意 的语义Return是模糊的;它们记录在您提供的链接中。简而言之,Return退出调用它的最内部构造(即控制结构或函数定义)。
CleanUp上面的函数无法从 a 中清理的唯一情况Return是当您直接传递单个 or CompoundExpression(例如(one;two;three)直接作为其输入。
Return 退出函数f:
In[28]:= f[] := Return["ret"]
In[29]:= CleanUp[f[], Print["cleaned"]]
During evaluation of In[29]:= cleaned
Out[29]= "ret"
Run Code Online (Sandbox Code Playgroud)
Return退出x:
In[31]:= x = Return["foo"]
In[32]:= CleanUp[x, Print["cleaned"]]
During evaluation of In[32]:= cleaned
Out[32]= "foo"
Run Code Online (Sandbox Code Playgroud)
Return退出Do循环:
In[33]:= g[] := (x = 0; Do[x++; Return["blah"], {10}]; x)
In[34]:= CleanUp[g[], Print["cleaned"]]
During evaluation of In[34]:= cleaned
Out[34]= 1
Run Code Online (Sandbox Code Playgroud)
从 的 主体返回CleanUp被评估的点body(因为CleanUp是HoldAll):
In[35]:= CleanUp[Return["ret"], Print["cleaned"]];
Out[35]= "ret"
In[36]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[36]:= before
Out[36]= "ret"
Run Code Online (Sandbox Code Playgroud)
正如我上面指出的,后两个示例是我可以设计的唯一有问题的情况(尽管我可能是错的),但可以通过添加定义来处理它们CleanUp:
In[44]:= CleanUp[CompoundExpression[before___, Return[ret_], ___], form_] :=
(before; form; ret)
In[45]:= CleanUp[Return["ret"], Print["cleaned"]]
During evaluation of In[46]:= cleaned
Out[45]= "ret"
In[46]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[46]:= before
During evaluation of In[46]:= cleaned
Out[46]= "ret"
Run Code Online (Sandbox Code Playgroud)
正如您所说,不会赢得任何选美比赛,但希望这有助于解决您的问题!
回复您的更新
我认为使用ReturninsideIf是不必要的,甚至是滥用Return,因为If已经根据第一个参数中的条件状态返回了第二个或第三个参数。虽然我意识到你的例子可能是人为的,If[3==3, Return["Foo"]]但功能上与If[3==3, "foo"]
如果你有一个更复杂的If语句,你最好使用Throw和Catch来打破评估并将某些内容“返回”到你想要它返回的点。
也就是说,我意识到您可能并不总是能够控制之后必须清理的代码,因此您始终可以将表达式包装在CleanUp无操作控制结构中,例如:
ret1 = Do[ret2 = expr, {1}]
Run Code Online (Sandbox Code Playgroud)
...通过滥用Do强制Return不包含在控制结构中的expr返回到Do循环之外。唯一棘手的部分(我认为,没有尝试过)是必须处理上面的两个不同的返回值:ret1将包含 uncontained 的值Return,但ret2将具有 的任何其他评估的值expr。可能有一种更干净的方法来处理这个问题,但我现在看不到。
哈!
| 归档时间: |
|
| 查看次数: |
1175 次 |
| 最近记录: |