Wolfram mathematica Mathematica作业中不需要的评估:为什么会发生,以及如何在包加载期间调试?
我正在开发一个(大)包,它不能再正常加载了。 这是在我更改了一行代码之后发生的。 当我尝试加载包(带有需求)时,包开始加载,然后其中一个setdelayed定义“变得活跃”(即,以某种方式被评估),被困在前几行加载的错误捕获例程中,包加载中止。Wolfram mathematica Mathematica作业中不需要的评估:为什么会发生,以及如何在包加载期间调试?,wolfram-mathematica,workbench,Wolfram Mathematica,Workbench,我正在开发一个(大)包,它不能再正常加载了。 这是在我更改了一行代码之后发生的。 当我尝试加载包(带有需求)时,包开始加载,然后其中一个setdelayed定义“变得活跃”(即,以某种方式被评估),被困在前几行加载的错误捕获例程中,包加载中止。 带有abort的错误捕获例程正在执行它的工作,只是在包加载阶段不应该首先调用它。 错误消息显示错误的参数实际上是一个模式表达式,几行之后我在setdelayed定义的lhs上使用了它 大概是这样的: ……Some code lines Changed
带有abort的错误捕获例程正在执行它的工作,只是在包加载阶段不应该首先调用它。 错误消息显示错误的参数实际上是一个模式表达式,几行之后我在setdelayed定义的lhs上使用了它 大概是这样的:
……Some code lines
Changed line of code
g[x_?NotGoodQ]:=(Message[g::nogood, x];Abort[])
……..some other code lines
g/: cccQ[g[x0_]]:=True
Clear[g,notGoodQ];
notGoodQ[x_]:=EvenQ[x];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
g/:cccQ[HoldPattern[g[x0_]]]:=True;
当我尝试加载包时,我得到:
g::nogood: Argument x0_ is not good
正如您所看到的,传递的参数是一种模式,它只能来自上面的代码行
我试图找出这种行为的原因,但到目前为止我一直没有成功。
所以我决定使用功能强大的工作台调试工具
我想一步一步地(或通过断点)看看加载包时会发生什么。
我还不太熟悉WB,但似乎使用Debug as…,首先加载包,然后最终使用断点等进行调试。
我的问题是,包甚至没有完全加载!加载包之前设置的任何断点似乎都无效
所以…2个问题:
Holdpattern
,只需在g的下行值之前定义g的上行值
notGoodQ[x_] := EvenQ[x];
Clear[g];
g /: cccQ[g[x0_]] := True
g[x_?notGoodQ] := (Message[g::nogood, x]; Abort[])
现在
当
所以……一般规则:
编写函数g时,首先为g定义UpValue,然后为g定义DownValue,否则使用Holdpattern
你能遵守这条规则吗
Leonid说使用Holdpattern
可能意味着可以改进设计。除了上面提到的解决方案外,如何改进上面的小代码的设计,或者更好地说,在处理upvalues时,如何改进一般代码的设计
感谢您的帮助抛开WB(回答您的问题并不真正需要WB)-这个问题似乎只有一个简单的答案,即仅基于作业期间表达式的计算方式。以下是一个例子:
In[1505]:=
notGoodQ[x_]:=True;
Clear[g];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
In[1509]:= g/:cccQ[g[x0_]]:=True
During evaluation of In[1509]:= g::nogood: -- Message text not found -- (x0_)
Out[1509]= $Aborted
In[1513]:=
ClearAll[h,f];
h[___]:=Print["Evaluated"];
In[1515]:= h/:f[h[1,2]]:=3
During evaluation of In[1515]:= Evaluated
During evaluation of In[1515]:= TagSetDelayed::tagnf: Tag h not found in f[Null]. >>
Out[1515]= $Failed
为了让它工作,我特意为notGoodQ
定义了一个总是返回True
。现在,为什么在分配期间通过TagSetDelayed
对g[x0\ux0]
进行评估?答案是,虽然作业h/:f[h[elem1,…,elemn]]:=…
中的TagSetDelayed
(以及SetDelayed
)没有应用f
可能具有的任何规则,但它将计算h[elem1,…,elem2]
,以及f
。以下是一个例子:
In[1505]:=
notGoodQ[x_]:=True;
Clear[g];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
In[1509]:= g/:cccQ[g[x0_]]:=True
During evaluation of In[1509]:= g::nogood: -- Message text not found -- (x0_)
Out[1509]= $Aborted
In[1513]:=
ClearAll[h,f];
h[___]:=Print["Evaluated"];
In[1515]:= h/:f[h[1,2]]:=3
During evaluation of In[1515]:= Evaluated
During evaluation of In[1515]:= TagSetDelayed::tagnf: Tag h not found in f[Null]. >>
Out[1515]= $Failed
TagSetDelayed
是HoldAll
这一事实并不意味着它不计算它的参数-它只意味着参数到达它时没有计算,它们是否会被计算取决于TagSetDelayed
的语义(我在上面简要描述过)。这同样适用于SetDelayed
,因此常用的语句“不计算其参数”在字面上是不正确的。更正确的说法是,它接收未计算的参数,并以一种特殊的方式计算它们——不计算r.h.s,而对于l.h.s,计算head和元素,但不为head应用规则。为了避免这种情况,您可以将内容包装在HoldPattern
中,如下所示:
……Some code lines
Changed line of code
g[x_?NotGoodQ]:=(Message[g::nogood, x];Abort[])
……..some other code lines
g/: cccQ[g[x0_]]:=True
Clear[g,notGoodQ];
notGoodQ[x_]:=EvenQ[x];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
g/:cccQ[HoldPattern[g[x0_]]]:=True;
这件事过去了。以下是一些用法:
In[1527]:= cccQ[g[1]]
Out[1527]= True
In[1528]:= cccQ[g[2]]
During evaluation of In[1528]:= g::nogood: -- Message text not found -- (2)
Out[1528]= $Aborted
但是请注意,在进行定义时,左手边需要HoldPattern
,这通常是一个信号,表明在函数调用过程中,头部的表达式也可能会求值,这可能会破坏代码。以下是我的意思的一个例子:
In[1532]:=
ClearAll[f,h];
f[x_]:=x^2;
f/:h[HoldPattern[f[y_]]]:=y^4;
此代码试图捕获像h[f[something]]
这样的情况,但显然会失败,因为f[something]
将在计算到h
之前进行计算:
In[1535]:= h[f[5]]
Out[1535]= h[25]
对我来说,l.h.s.需要HoldPattern
,这表明我需要重新考虑我的设计
编辑
关于在WB中加载期间的调试,您可以做的一件事(IIRC,现在不能检查)是使用良好的旧打印语句,其输出将显示在WB的控制台中。就我个人而言,我很少觉得有必要为此使用调试器(加载时调试包)
编辑2
针对问题中的编辑:
关于定义的顺序:是的,你可以这样做,它解决了这个特殊的问题。但是,一般来说,这是不健全的,我不认为这是一个好的一般方法。对于手头的案件很难给出明确的建议,因为它有点脱离上下文,但在我看来,这里使用UpValues
是不合理的。如果这是为了错误处理而做的,那么就不需要使用UpValues
通常,UpValues
最常用于以安全的方式重载某些函数,而不向重载的函数添加任何规则。一个建议是避免将UpValues
与同样具有DownValues
且可能进行评估的头部相关联-这样做,您就开始与evaluator玩游戏,最终将失败。最安全的方法是将upvalue
附加到惰性符号上(he