打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Mathematica自带调试器的使用
0. 引言

我发现我过去在这帖这帖中提到过的对Mathematica自带调试器的看法恐怕该收回了:Mathematica的自带调试器并不渣,只是我们的用法不对。故撰此文说说它的正确用法。

不过,这里还是要强调一下,只要善用笔记本(.nb文件)的动态交互特性,就能写出几乎无需调试的代码。学会用笔记本(.nb文件)远比学会调试器的使用来得重要。不知道我这段是在说啥的请先看一下这帖再继续。

1. 基础用法

这一部分系自这帖这帖翻译增补而来。

简洁版:

别管断点!把“在提示信息处中断”勾上!

……看不懂的继续往下看

详细版:

1. 总之我们先点击顶部菜单的 计算 -> 调试 ,打开调试器:

2. 在打开的面板中,把“在提示信息处中断”给勾上:

3. 下面就可以开始调试了。如今的Mathematica一般就会在会产生提示信息(你或许比较熟悉“警告信息”“报错”之类的叫法)的地方暂停。举个例子:
Table[a = 1;
b = {2, 3} c = i;, {i, 2}]

4. 停下来之后我们一般会想知道到底是哪个地方产生了警告。上面这段代码很简单,我们扫一眼就能发现问题所在,但是这招显然对比较长的代码不那么有效,那么有没有更好的办法?当然是有的。让我们点击面版上的显示堆栈:
接着就会弹出这么一个窗口:
我们把页面拉到最底下:
没错,这里就是计算停下的地方,那么有没有办法知道这计算具体是停在了原代码中的哪里呢?当然是有的。你有没有发现上面的倒数第3行其实是个按钮?:
只要点它一下,原代码中的相应部分就会高亮:
于是出问题的位置就被我们找到了。

注意,在调试期间,我们是可以获知函数内的局部变量取值的:
当然了,Table的局部化是基于Block的,基于Module的局部化的情况和这不太一样:
Module[{i}, For[i = 1, i < 3, i++, a = 1;
b = {2, 3} c = i;]]

但是,这也只是没法用这种方法读。对于这一情况我们有更简单的方法——堆栈窗口可以直接看局部变量:


5. 接下来只需要点击调试面板上的 结束 或 放弃 (这两个键的具体作用在气泡提示里已经说的很清楚了),再回头修改错误的代码就行了。

2. 进阶:断点的正确设置方法

对于设置断点(即面板上的“在选择处加断点”连带“显示断点”这两个按钮), Szabolcs的建议是别去碰。这个建议是有其道理的,因为我们希望程序暂停的地方通常就是出警告的地方,上面介绍的方法已经够用了,并且,很多时候程序似乎并不会在我们设的断点处停下……(大部分尝试使用调试器的人都是跪在这一步。)不过,经过尝试,我想我已经探明了断点的正确设置方法。总结起来就是:

1. “一段完整的代码”无法设为断点。例如:
a + b
c + d

a+b这个断点不会起效,因为它已经是一段完整的代码了,而断点似乎只能设在子表达式上,不管是怎样的子表达式,比如我们可以对上面的代码做一个非常细小的修改:
a + b;
c + d
这下断点就能生效了:


为什么?因为 ; 也是个函数啊,现在a+b不再是段完整的代码了。不知道 ; 是什么函数的人请翻自带帮助。

1.1. 形如 (a + b) 的头部或是函数参数内的 a + b 无法被设为断点。例如:
(1 + 1)[d]
d[(1+1)]

我认为这个应该算第1点的子规则——调试器大概觉得这样的头部也算一段完整代码。注意这里只要把选择范围增大一点点即将小括号也包括在内,这个断点就会生效:


1.1.1 不过注意对于小括号有个例外情况

如果小括号外面已经啥也没有了,那么在小括号内设断点又反而可以生效了:


2. 原子表达式(Atom)无法被设为断点。依旧用上面的例子:

a显然不是“完整代码”(它是Plus[a,b]的子表达式),但这个断点没生效,因为a是个原子表达式:

不是原子的话就能停了:


注意,Mathematica在判断是否为原子表达式时看的只是显式结构,也就是说
a = e + f;
a + b; c
的a点照样是停不了的。因为这里的a只有在计算之后才会变成非原子表达式:

但是,难道我们就对原子表达式无能为力了吗?当然不是的!至少对于头部为Symbol的原子是这样。头部(Head)为Symbol的原子表达式(实际上似乎也只有原子表达式)虽然不能被设为断点,却可以被设为观察点:观察点的设置位置在哪呢?首先点面板上的显示断点:

新出现的页面的最下方就是观察点的设置位置:

我们随便在添加表达式这栏填上想观察的原子表达式再回车,这里就会变成这样:
现在我们勾的是赋值时中断,如果这时候执行d=1之类的语句我们就会看到:

不过注意,延迟赋值SetDelayed,即d:=1不会被中断,大概是因为计算被延迟了所以没被算进赋值里去。

勾的是执行时中断的话效果就是这样:
还有“作为函数使用时”中断:


注意,全体内置函数和内置符号也是头部为Symbol的原子表达式,也就是说,我们可以依靠观察点做到类似这样的事:


查看堆栈,你会发现计算停在了Plus这个头部计算时:


通过设置观察点,我们也可以做到执行一行就自动暂停一次。(虽然我依旧认为大家应该把“执行一行停一次”的工作在写代码的时候就做完。)你只需要:
1. 先在$Post里存个输入等于输出的函数:
$Post=#&;
然后把$Post设为观察点,再把“执行时中断”给勾上就行了。(想要从一行前进到另一行,只需按“继续”就行)

顺便虽然觉得读到这里的读者也该明白了,这里还是再强调一次:Mathematica里的代码的行,不是以换行来界定的,而是以一段代码是否是其他函数的参数或头部决定的,例如
Table[a = 1;
b = {2, 3}
c = i;, {i, 2}]
就只是一行代码,而非三行。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
除错专家---程序调试的利器GDB
使用Eclipse调试Java程序代码
VC++一些常用调试方法
GDB框架过程概述
11个强大的Visual Studio调试小技巧
C# 的快捷键汇总(一)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服