Prolog的数据结构
在这之前我们只涉及了Prolog程序中简单的数据形式,这种数据只有一项,因此是非结构的,然而有必要将对象或整汇集到一起。在这篇经验中,我将介绍它的结构和表的特性。

2、现在如果打算询问知识库中每个人的头发颜色,我们不得不这样提问:?- has(X,Y).并不断在提示符“?”后键入“;”,迫使回溯。会话过程如图所示。正如读者所看到的,这样将导致大量不必要的信息输出。这是因为数据是非结构化的,因而无法较为明确地询问。

4、现在为了了解知识库里每个人头发的颜色,我们可以简单地提出询问:?- has(X, hair(Y)).然后再要求Prolog在每个回答之后进行回溯,会话过程如图所示。这些信息不多不少正是我们想要的。

2、表头和表尾的概念是理解Prolog中表处理的基础。表头是一个元素,而表尾本身是一个表。表具有递归的数据结构,因为它是由表头和另一个表(表尾)组成的。正像其递归结构那样,表也可以递归定义。比如:考虑到[a, b, c],该表表头=a,表尾=[b, c];表尾也是一个表,表头 = b,表尾=[c];而表尾[c],也是一个表,表头=c,表尾=[ ]。由于[ ]是个空表,所以递归过程到此为止。空表可视为停止条件。若用H表示表头,T表示表尾,则表记作:[H|T]其中竖线“|”是Prolog中用于分隔表头和表尾的符号。下图是对上一个例子询问的结果,注意观察匹配模式。其中“_”为空变量,表示不关心该位置上的元素。

2、这是它的运行结果。Prolog对答案搜索的过程如下:进入知识库,试图与规则一匹配,因为目标与表头不同,故失败;继续搜索,试图与规则二匹配,目标和表尾作为参数,重新回到规则一,直到成功。

4、对于它的工作机制,不妨先从特殊到一般的规则来了解。❶编写一个规则concatenate(List1, List2, List3). ,它可以将一个空列表与List1连接在一起。这一点很容易,concatenate([ ], List, List).就可以做到,当执行addto时,List3会和要追加的List2相同;❷添加一个规则,它可以将List1中的一个元素与List2连接在一起:concatenate([Head|[]], List, [Head|List]).;❸添加一个规则,它可以将List1中的两个元素或三个元素与List2连接在一起;❹泛化这些规则,转化递归形式,最终形成上图中的代码。

6、以上规则是基于这样的思想,即可以通过把一个表头追加到该表的表尾的反序表上,达到反序的目的。谓词reverse的第一个变元缩减到空表时,满足停止条件,停止条件还可以表述为空表的反序仍为空表本身。下图是程序的运行结果。在导入程序时要注意文件的顺序。

8、SWI-Prolog内置了丰富的处理列表的库,比如member就是用于查看元素是否属于列表,append用于追加列表,reverse用于倒序列表。你可以在SWI-Prolog的网站上的library(lists): List Manipulation页面上查找更多。
