计算的跟踪

Wolfram 系统运行的标准方式是将任何表达式看作输入,计算它们的值并给出结果. 为了观察 Wolfram 系统的运行过程,不仅需要知道运行结果,还要知道中间的计算步骤.

Trace[expr]产生在 expr 计算过程中使用的表达式列表
Trace[expr,form]仅包括与模式 form 匹配的表达式

跟踪表达式的计算.

立即求出 的结果 .
In[1]:=
Click for copyable input
Out[1]=
在加法前计算 .
In[2]:=
Click for copyable input
Out[2]=
每个子表达式的计算显示在不同的子列中.
In[3]:=
Click for copyable input
Out[3]=

Trace[expr] 给出 expr 计算过程中涉及的所有 中间表达式. 除了特别简单的情形,所产生的这些中间表达式非常多,这使Trace 的返回值不容易理解.

Trace[expr,form] 可以滤掉一部分 Trace 所记录的表达式,仅保存与模式 form 匹配的那一部分表达式.

阶乘函数的递推定义.
In[4]:=
Click for copyable input
Out[4]=
这里给出了计算 过程中的所有 中间表达式. 结果相当复杂.
In[5]:=
Click for copyable input
Out[5]=
此处仅显示了形如 的中间表达式.
In[6]:=
Click for copyable input
Out[6]=
Trace 中可以任意指定模式.
In[7]:=
Click for copyable input
Out[7]=

Trace[expr,form] 仅选择出 expr 计算过程中与模式 form 匹配的那些表达式.

需要跟踪 等函数的调用情况时,就可以用 Trace 去挑选出形如 的表达式. 也可以用模式 去选出具有某一自变量的调用.

典型的 Wolfram 系统程序不仅有函数调用,如 ,而且有变量赋值、控制结构等语句. 这些语句都被看作为表达式,所以,能在 Trace 中选出任何 Wolfram 系统程序元素. 例如,模式 可以选出对符号 的所有赋值.

显示了对 的赋值序列.
In[8]:=
Click for copyable input
Out[8]=

Trace[expr,form] 能选出 expr 计算过程中出现的表达式. 这些表达式不必直接出现在给出的 expr 形式中. 它们也有可能在 expr 计算的部分过程中被调用的时候出现.

定义一个函数.
In[9]:=
Click for copyable input
查看 计算过程中产生的表达式.
In[10]:=
Click for copyable input
Out[10]=

Trace 可以监视自定义函数和 Wolfram 系统内部函数计算的中间步骤. 而且,Wolfram 系统内部函数的中间步骤序列与 Wolfram 系统具体版本的实现和优化细节有关.

Trace[expr,f[___]]显示 f 的调用
Trace[expr,i=_]显示 i 的赋值
Trace[expr,_=_]显示所有的赋值
Trace[expr,Message[___]]显示所有产生的信息

使用 Trace 的一些方式.

Trace 函数的返回值是一个列表,它反映了 Wolfram 系统的计算过程. 在这个列表中的表达式按照计算过程中产生的顺序排列. 大部分情况下,Trace 返回的列表具有嵌套结构,这反映了计算过程中的结构.

其基本思想是,在 Trace 返回值列表中的子列表代表一个 Wolfram 系统表达式的计算序列. 这个序列的不同元素代表同一表达式的不同形式. 通常一个表达式的计算涉及到几个其它表达式的计算. 每个计算对应于由 Trace 返回的结构中的一个子列.

这里给出一个赋值序列.
In[11]:=
Click for copyable input
Out[11]=
这里产生一个反映 a[i] 变换序列的计算链.
In[12]:=
Click for copyable input
Out[12]=
化简过程中产生的序列反映这个计算链中的元素.
In[13]:=
Click for copyable input
Out[13]=
函数 的每个变量有一个计算链,这些链由子列给出.
In[14]:=
Click for copyable input
Out[14]=
每个子表达式的计算链在不同的子列中给出.
In[15]:=
Click for copyable input
Out[15]=
跟踪一个嵌套表达式给出了一个嵌套列表.
In[16]:=
Click for copyable input
Out[16]=

在 Wolfram 系统表达式的计算中有两种情况需辅助计算. 第一种情况是要计算该表达式所包含的一些子表达式,第二种情况在表达式计算中有一些规则,这些规则又要求计算其它一些表达式. 这两种辅助计算都反映在 Trace 返回值的子列中.

这是由 的变量的计算所产生的子计算.
In[17]:=
Click for copyable input
Out[17]=
附加了一个条件的函数.
In[18]:=
Click for copyable input
的计算涉及到与该条件有关的子计算.
In[19]:=
Click for copyable input
Out[19]=

在跟踪由递推定义的函数计算时,就会得到嵌套列表. 其原因是函数的形式在递推过程中反复出现.

例如,当定义 时,计算 时产生表达式 ,其中 是一个子表达式.

这是计算 时产生的嵌套子列.
In[20]:=
Click for copyable input
Out[20]=
由定义 可作为 fp[n] 的值来得到.
In[21]:=
Click for copyable input
子表达式中不出现 fp[n],因此没有子列表生成.
In[22]:=
Click for copyable input
Out[22]=
这里给出 Fibonacci 数的递推定义.
In[23]:=
Click for copyable input
这里给出递推结束的条件.
In[24]:=
Click for copyable input
Out[24]=
显示在 递推计算中的所有步骤.
In[25]:=
Click for copyable input
Out[25]=

Wolfram 系统表达式计算的每一步可以看作一个变换规则的使用. 正如 "与不同符号相关的定义" 中所述,Wolfram 系统中的规则与特定符号或标志相联系. 可以使用 Trace[expr,f] 去观察与符号 f 相联系的变换规则作用于 expr 的计算步骤. 在这种情况下,Trace 不仅给出了使用每个规则的表达式序列,而且给出了使用这些规则的结果.

一般来说,Trace[expr,form] 选出计算 expr 的所有步骤,其中 form 与要计算的表达式匹配,或与所使用的规则相联系的标志匹配.

Trace[expr,f]显示使用与 f 有关的变换规则的计算
Trace[expr,f|g]显示所有与 fg 有关的计算

跟踪与特定标志联系的计算.

仅显示与 匹配的中间表达式.
In[26]:=
Click for copyable input
Out[26]=
显示使用所有与符号 有关的变换规则的计算.
In[27]:=
Click for copyable input
Out[27]=
这是 函数的规则.
In[28]:=
Click for copyable input
跟踪 的计算过程,显示与 有关的所有变量.
In[29]:=
Click for copyable input
Out[29]=
Trace[expr,form,TraceOn->oform]转向仅跟踪与 oform 匹配的形式
Trace[expr,form,TraceOff->oform]停止跟踪与 oform 匹配的形式

关闭某些形式内部的跟踪.

Trace[expr,form] 跟踪计算 expr 过程任何点产生的与 form 匹配的表达式. 有时候,也需要跟踪在计算 expr.

通过设置 TraceOn->oform,就可以仅跟踪与 oform 匹配的表达式计算. 同样,通过设置 TraceOff->oform,就可以不用跟踪与 oform 匹配的表达式计算.

显示计算的所有步骤.
In[30]:=
Click for copyable input
Out[30]=
仅显示 计算过程中的步骤.
In[31]:=
Click for copyable input
Out[31]=
仅显示不在 计算过程中的步骤.
In[32]:=
Click for copyable input
Out[32]=
Trace[expr,lhs->rhs]找出在 expr 计算过程中遇到的与 lhs 匹配的所有表达式,并用 rhs 替换它们

将规则运用到计算过程中遇到的表达式.

Trace 仅给出计算 过程中所用到的 的变量.
In[33]:=
Click for copyable input
Out[33]=

Wolfram 系统函数 Trace 的返回值基本上是一个标准的 Wolfram 系统表达式. 它可以由其它函数调用,这是 Trace 函数的一个强大功能. 但要注意,Trace 将列表中产生的所有表达式用 HoldForm 封装起来使其不计算. HoldForm 不在 Wolfram 系统标准输出中显示,但它仍在表达式的内部结构中存在.

这里显示了计算过程中中间步骤的表达式.
In[34]:=
Click for copyable input
Out[34]=
这些表达式用 HoldForm 封装,使得它们不被计算.
在 Wolfram 系统的标准输出中,有些难以区别哪些列表是与 Trace 的返回结构相关,哪些是正在计算的表达式.
In[36]:=
Click for copyable input
Out[36]=
这里的输入解决了上面的二义性问题.
Trace 中使用变换规则时,在用 HoldForm 封装之前先计算结果.
In[38]:=
Click for copyable input
Out[38]=

在复杂的计算中,由 Trace 返回的列表结构可能是相当复杂的. 当使用 Trace[expr,form] 时,Trace 给出仅与模式form 匹配的表达式列表. 不管给出的是什么模式,列表的结构是相同的.

这里显示在 计算中出现的所有 .
In[39]:=
Click for copyable input
Out[39]=
这里仅显示了 ,但列表的结构与 的相同.
In[40]:=
Click for copyable input
Out[40]=

可选项 TraceDepth->n 使 Trace 仅跟踪到嵌套列表中的第 n 层. 用这种方式,能观察到计算过程中的主要步骤,而忽略一些细节. 用 TraceDepthTraceOff 可以不跟踪计算过程中的一些步骤,使 Trace 的运行加快.

这里仅显示了嵌套列表中前2层.
In[41]:=
Click for copyable input
Out[41]=
Trace[expr,form,TraceDepth->n]不跟踪 expr 计算过程中第 n 层以后的步骤

跟踪层次的限制.

Trace[expr,form] 得到计算 expr 过程中与 form 匹配的所有表达式列表. 有时,不仅需要观察这些表达式,也需要通过这些表达式计算得到的结果. 这可以在 Trace 中设置可选项 TraceForward->True 来实现.

这里不仅显示了与 匹配的表达式,而且给出了它们的计算结果.
In[42]:=
Click for copyable input
Out[42]=

Trace[expr,form] 能得到计算链中间的表达式,设置 TraceForward->True 可以令 Trace 包含计算链末尾的表达式. 设置 TraceForward->All 可使 Trace 显示计算链中出现与 form 匹配的表达式之后的所有表达式.

TraceForward->All 来包含计算链中与 匹配后的所有元素.
In[43]:=
Click for copyable input
Out[43]=

通过设置 TraceForward,就可以在计算过程中有效地观察到某一特定表达式的计算. 有时不需要知道某一表达式的计算,而是关心它的生成过程. 这可以用可选项 TraceBackward 来实现. TraceBackward 显示一个计算链中某特定表达式之前的情况.

这里表示 来源于 的计算中对 的计算.
In[44]:=
Click for copyable input
Out[44]=
这里显示了与产生 有关的计算链.
In[45]:=
Click for copyable input
Out[45]=

TraceForwardTraceBackward 可以使我们观察计算链中一个表达式前后的情形,有时还需要观察包含某一特定表达式的计算链,可以用 TraceAbove 来完成这一任务. 可选项 TraceAbove->TrueTrace 包含相关计算链的首尾表达式. 使用 TraceAbove->AllTrace 包含这个计算链中的所有表达式.

这里包含了 计算链中的首尾表达式.
In[46]:=
Click for copyable input
Out[46]=
显示计算 过程中生成 的所有方式.
In[47]:=
Click for copyable input
Out[47]=
Trace[expr,form,opts]使用指定选项跟踪 expr 的计算
TraceForward->True包括含有 form 的计算链中的最后一个表达式
TraceForward->All包括计算链中 form 以后的所有表达式
TraceBackward->True包括含有 form 计算链的第一个表达式
TraceBackward->All包括计算链中 form 以前的所有表达式
TraceAbove->True包括所有含 form 的计算链中的首尾表达式
TraceAbove->All包括所有含 form 的计算链中所有表达式

跟踪表中可选项的设置.

Trace[expr,] 工作的基本方式是截取 expr 计算过程中所遇到的每一个表达式,然后用各种判据去确定是否记录该表达式. 然后,Trace 一般在函数变量计算完成 截取表达式. 通过使用可选项 TraceOriginal->True 能使 Trace 跟踪函数变量计算之前 的表达式.

这里包括了变量计算前后与 匹配的表达式.
In[48]:=
Click for copyable input
Out[48]=

Trace 得到的列表结构中一般仅包含非平凡计算链中的表达式,例如,单个符号自身的计算不包括在内. 但设置了TraceOriginal->True 之后,Trace 就跟踪计算过程中的每一个表达式,包括平凡计算链中的表达式.

这里 Trace 跟踪所有表达式,包括平凡计算链内的表达式.
In[49]:=
Click for copyable input
Out[49]=
可选项名
默认值
TraceForwardFalse是否显示计算链中 form 后的表达式
TraceBackwardFalse是否显示计算链中 form 前的表达式
TraceAboveFalse是否显示引出含有 form 计算链的计算链
TraceOriginalFalse是否在表达式的头部或变量计算之前跟踪表达式

Trace 的附加可选项.

当使用 Trace 去考察程序的执行时必然涉及到局部变量的处理. 正如 "模块工作方式" 所述,Mathematica 中的Module 等产生一些新符号来表示局部变量. 于是,即使在原代码中变量名为 ,在执行过程中会被重命名为 等.

跟踪 Trace[expr,form] 的设置规律,出现在 form 中的 x 将与 expr 执行中出现的所有形如 的符号相匹配. 例如,使用 Trace[expr,x=_] 可以跟踪原程序中所有变量(全局或局部)x 的赋值过程.

Trace[expr,form,MatchLocalNames->False]
包含了与 form 匹配的 expr 执行过程中所有步骤,但不能用局部变量名替换

禁止与局部变量匹配.

有时,仅需要跟踪全局变量 x,不跟踪名为 x 的局部变量,这可以通过设置可选项 MatchLocalNames->False 来实现.

跟踪所有名为 变量的赋值.
In[50]:=
Click for copyable input
Out[50]=
仅对全局变量 x 的赋值进行跟踪.
In[51]:=
Click for copyable input
Out[51]=

Trace 函数进行彻底的计算,返回值是代表这个计算过程的结构. 在很长的计算中,有必要跟踪计算进程. 函数TracePrintTrace 相似,但它显示所遇到的表达式,而不像 Trace 那样保存这些表达式去产生一个结构.

显示在 计算中出现的表达式.
In[52]:=
Click for copyable input
Out[52]=

TracePrint 显示的表达式序列与 Trace 返回的列表结构中的表达式序列相对应. TracePrint 输出中的缩进形式与Trace 列表结构中的嵌套相对应. 在 TracePrint 中也可以使用 Trace 的可选项 TraceOnTraceOffTraceForward. 但由于 TracePrint 随着进程产生输出,所以它不能用可选项 TraceBackward. 另外,总是把 TracePrint 设置成 TraceOriginal 值为 True.

Trace[expr,]跟踪 expr 的计算过程,返回值是包含所出现表达式的一个列表结构
TracePrint[expr,]跟踪 expr 的计算,显示所遇到的表达式
TraceDialog[expr,]跟踪 expr 的计算,当每个指定的表达式出现时产生一个对话
TraceScan[f,expr,]跟踪 expr 的计算,对遇到表达式的 HoldForm 运用 f

跟踪计算函数.

的计算过程中出现 时显示一个对话.
In[53]:=
Click for copyable input
Out[53]=
在对话中通过查看stack就可以发现当前在何处.
In[54]:=
Click for copyable input
Out[54]=
从对话中返回,给出 的计算结果.
In[55]:=
Click for copyable input
Out[55]=

函数 TraceDialog 可以暂停计算,并对 Wolfram 系统当时环境进行处理. 例如,得到计算过程中中间变量的值,甚至重新设置它们的值. 当然还有许多辅助作用,大部分都与模式或模块有关.

TraceDialog 的功能是在一个表达式列中调用 Dialog 函数. Dialog 函数将在 "对话" 节仔细讨论. 在调用Dialog 时就开始了一个具有自己输入和输出列的 Wolfram 系统辅助进程.

跟踪计算时,一般需要对所得到的表达式运用一个任意函数. TraceScan[f,expr,]f 作用于所出现的每个表达式上,用 HoldForm 封装的表达式不计算.

TraceScan[f,expr,] 中,函数 f 在表达式被计算之前作用于该表达式,而 TraceScan[f,expr,patt,fp] 在计算之前作用于 f,而在计算之后作用于 fp.