Debugging 调试命令行程序
如果我有一个用作命令行工具的程序,我的调试选项是什么 为了便于示例,让我们假设程序如下所示Debugging 调试命令行程序,debugging,prolog,swi-prolog,failure-slice,zebra-puzzle,Debugging,Prolog,Swi Prolog,Failure Slice,Zebra Puzzle,如果我有一个用作命令行工具的程序,我的调试选项是什么 为了便于示例,让我们假设程序如下所示 do_stuff.pl列表: main :- current_prolog_flag(argv, Argv), do_stuff(Argv), halt. main :- halt(1). 使用SWI Prolog,我可以用以下方法编译: swipl --goal=main -o do_stuff -c do_stuff.pl 我只要打个电话就可以运行它 $ ./do_
do_stuff.pl
列表:
main :-
current_prolog_flag(argv, Argv),
do_stuff(Argv),
halt.
main :-
halt(1).
使用SWI Prolog,我可以用以下方法编译:
swipl --goal=main -o do_stuff -c do_stuff.pl
我只要打个电话就可以运行它
$ ./do_stuff foo bar baz
目前,如果do_stuff/1
失败,将以1退出。我怎样才能看到第一个(最早、最深的)失败的目标?或者更好,整个回溯?我假设我应该能够使用debug
和leash
,例如:
main :-
current_prolog_flag(argv, Argv),
debug, leash(+fail),
do_stuff(Argv),
halt.
。。。但我没有尝试过任何有效的方法
我唯一一个半途而废的想法是,对我期望在确定性上成功但没有成功的每个谓词都抛出一个错误。这当然是可行的,但似乎有点过分
动机
用作命令行工具的程序(通常)要运行一次,获取其参数,读取其输入,写入输出。在这种情况下,失败意味着什么?我的理解是,意外的失败是程序中的错误
单元测试可能会有所帮助(单独测试谓词);但是,根据定义,这对由于程序员对问题、范围或工具缺乏了解而导致的错误没有帮助。只有使用真实输入运行程序才能捕获此类错误
因此,在上面的例子中,如果某个用例导致do_stuff/1
失败,并且程序以非零代码退出,那么程序员在确定哪个谓词失败时有哪些选项
这个问题给出了一个解决方案。但是(如果我理解正确的话)这确实需要程序员系统地检查执行流,直到发现有问题的谓词调用为止
这正是我希望避免的。与更多面向命令的语言相比,失败在Prolog中是非常不寻常的事情。从第一天开始,人们就对它感兴趣。事实上,即使在Prolog 0(Prolog I之前的版本)中,在跟踪选项
ECRIRE
旁边也有一个特殊的选项僵局
,仅显示故障
后来,米雷尔·杜卡塞(Mirelle Ducasse)特别致力于自动找出故障的解释方法
失败的奇怪之处在于,它们并不一定表明出了什么问题。但有时,他们是
我要说的是,如何理解失败有两个不同的方向。第一个更具程序性,第二个更具声明性
注释
在许多项目中,我用它来表示我期望目标总是成功的。由于运算符声明,这只是一个额外字符:
...,
@goal_aux_togoalaux_spec(OQuery, FVect0, Query, Spec),
...
如果目标失败,则会发出错误消息。同样重要的是,还要记录嵌套异常。如果出现时间紧迫的问题,则必须删除这些@
。然而,我只是数了一下120kLOP中的~400
请注意,@
对于有多个答案的目标也很有效。喜欢
@成员(1[X,Y])
这种技术适用于事实上的moded程序。想一想准备一个(这就是上面的例子)。在这里,你主要在想:这是一个程序,什么是合适的切片?在这种情况下,“不,没有切片”不是答案。你真的希望它永远成功。如果您没有这样的模式程序,您通常可以通过强制执行稳定性来转换现有的未安装模式程序:
p(X, Y) :-
wellformed(X),
@p_old(X, Yc),
Yc = Y.
这种技术在纯关系、声明性代码中很快失去吸引力。看看这个。在那里,除了最初的目标之外,几乎不可能添加@
。在这种情况下,需要一种更具声明性的方法,如下所示
概括
对于更复杂的问题,@
的效果不太好。相反,需要对程序进行修改/切片。需要通过添加前缀*
来概括程序。有关此类调试会话的集合,请参阅,以便手动使用此技术。
这种技术的要点是,在确定最大泛化时,您不必理解程序的真正含义。你只需要关注失败的目标
理想情况下,这样的概括会自动产生。然而,还有很多障碍。首先,它们只适用于纯单调代码(事实上,这是一个很好的动机,为什么人们应该坚持这样的代码)。因此,首先必须对现有代码进行分析和分类。如果系统不符合要求并随机改变其行为(如您提到的系统),这就更加困难了。您看过吗?@false我以前见过这两个问题的答案。正如我所读到的,你的格式肯定比使用
格式更简洁,但并没有本质上的不同:我仍然需要自己寻找失败的根源。我遗漏了什么?@false,但我当然可以为“没有选择点的成功”定义一个符号/元谓词,并慷慨地使用它(也就是说,我知道的每个谓词都应该在没有选择点的情况下成功);这是一个合理的解决方案吗?我不确定“完全”决定论的这个属性是否有用,你应该一直测试它。我发现,通过偶尔测试,该属性相对容易维护。@false请参阅对我的问题的编辑,在那里我试图解释我的动机。因此,a)抛出任何应该总是成功一次的谓词,或b)开始在程序中查找错误。“随机改变他们的行为”这一点我没有体会到:几乎所有我有幸使用过的软件都有错误。找出错误是在您自己的代码中还是在其他地方是本练习的重点。@Bori