在学习Prolog的递归、列表之前,我们得先了解一下它的运行原理和调试。调试是排除程序中错误的过程,它是一种非常复杂的过程,特别是当开发的程序很长很复杂的时候更是如此,在这种情况下,明智的作法是把一个大程序分成许多较小的程序分别进行测试和调试。Prolog为用户提供了一系列的调试谓词,它们允许程序在执行的同时追踪Prolog的搜索过程。
工具/原料
电脑
SWI-Prolog
运行原理
1、在介绍调试谓词之前,了解一种用于描述Prolog程序控制流的图解表达方法是很有用的,这种表示方法通常称作“盒子模型(boxmodel)”。
2、盒子模型把一个谓词想象为一个盒子,Prolog解释程序的控制流通过这个盒子。如图所示,盒子的四个角上稳中有降有四个进、出端口,这些端口的含义分别是:CALL:Prolog为满足某个目标进入盒子时扬经过的端口;EXIT:Prolog在目标得到满足(即匹配成功)后离开盒子时所经过的端口;FAIL:Prolog在目标未能满足(即匹配失败)时退出盒子所经过的端口;REDO:Prolog为了再次满足某个目标进行回溯时,重新进入盒子的端口。
3、下面我们通过一个简单的实例来说明。Prolog谓词fish(X)匹配成功时,变量X例示为一种鱼。这里鱼被定义为一种体表有鳞片且无脊椎的动物。示例中,“tuna”为金枪鱼,“snake”为蛇,蛇属于爬行动物,是脊椎动物,因此蛇不会被匹配。
4、如果我们提出询问-?fish(X).程序执行所经过的路线如图所示。从图中可以看到,所要萍踪的总体目标fish(X)用最大的,即最外面的盒子A表示,子目标covered(X,scales)和invertebrate(X)分别用里面的两个盒子表示(盒子B和盒子C)。
5、初始询问导致对目标fish(X)的调用。这将控制进入盒子A的CALL端口,该CALL端口与B铜择珏觑盒子的CALL端口直接相连。例如,进入盒子B且目标成功,变量X例示可能“s荏鱿胫协nake”,但是盒子C无法与之匹配,因此控制流从盒子C的FAIL端口退出,进入盒子B的REDO端口,此时Prolog回溯,试图找到另一种长有鳞片的对象。X再次被例示为“tuna”,依次完成盒子B、C的匹配,最终从盒子A的EXIT端口退出,这时目标得到满足,Prolog给出答案:X=tuna.
调试谓词
1、载入程序文件后,为了实现调试洲訾惨赳功能,应当在运行程序前,在提示符“?-”后键入命令:trace.在某些版本的Prolog中,调试采用spy命令。调试程序对每个调用都寄噢剪飕在括号中给出一个数字。该数字表示调用的“深度”,即初始目标调用期间所做的目标调用次数。还需注意的是,变量用下划线和紧接其后的数字表示。在调试方面,感觉SWI-Prolog隐藏了一些东西,不如GNUProlog直观。图中“?”后的信息为用户键入的,其他为显示信息,在得出第一个答案后,要按“;”搜索另一个答案,其他按回车或“c”就可以继续。
2、在追踪程序时有几个不同的选择项,这些选择可以得到附加信息,或对程序执行实施进一步控遄咿湫幼制。每当到达盒子模型的某一端口后,调试程序给出提示符“?”。寄噢剪飕在提示符“?”后面键入一个字符便可以激活这些选项。常用的选择项如下:回车/c:继续;:回溯。转到当前目标的REDO端口;f:失败。转到当前目标的FAIL端口;r:重复。从EXIT端口转至该目标的CALL端口;s:跳。在目标的CALL端口告诉调试程序路过所有的提示符,直到该目标的EXIT或FAIL端口;L:显示当前谓词的全部子句;a:中止。返回Prolog环境;e:退出Prolog系统,它将放弃已做的全部工作;h:帮助。显示命令选项。