在这之前我们只涉及了Prolog法式中简单的数据形式,这种数据只有一项,是以长短布局的,然而有需要将对象或整汇集到一路。在这篇经验中,我将介绍它的布局和表的特征。

工具/原料
- SWI-Prolog
- 电脑
布局
- 1
Prolog供给了一种在谓词中成立布局的方式,即许可谓词的变元具有变元,从而达到使谓词变元具有布局的目标。用这种方式可以使谓词中具有的信息反映实际糊口中数据的现实关系。例如,考虑下面简单事实:
吉恩的头发是红色的。
显然,这个事其实Prolog中可以暗示为:
has(jean, red_hair).
还有其他一系列关于人以及他们的头发、眼睛颜色和其它表征他们属性的事实,常识库可能如图所示。

- 2
此刻若是筹算扣问常识库中每个人的头发颜色,我们不得不如许提问:
?- has(X,Y).
并不竭在提醒符“?”后键入“;”,迫使回溯。会话过程如图所示。
正如读者所看到的,如许将导致年夜量不需要的信息输出。这是因为数据长短布局化的,因而无法较为明白地扣问。

- 3
一种很是有效的,可切当地表达上述事实信息的方式如下:
has(jean, hair(red)).

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

表的根基概念
- 1
表是根基的数据布局,很多适用的Prolog法式都是成立在表的根本之上的,表是很多元素的简单调集。好比:
[red, yellow, green]
[1, 5, 68]
没有元素的表叫作空表,暗示为:
[ ]
下图是一行列表的代码。

- 2
表头和表从头至尾的概念是理解Prolog中表处置的根本。表头是一个元素,而表从头至尾自己是一个表。表具有递归的数据布局,因为它是由表头和另一个表(表从头至尾)构成的。正像其递归布局那样,表也可以递归界说。好比:
考虑到[a, b, c],该表表头=a,表从头至尾=[b, c];表从头至尾也是一个表,表头 = b,表从头至尾=[c];而表从头至尾[c],也是一个表,表头=c,表从头至尾=[ ]。
因为[ ]是个空表,所以递归过程到此为止。空表可视为遏制前提。
若用H暗示表头,T暗示表从头至尾,则表记作:
[H|T]
此中竖线“|”是Prolog顶用于分隔表头和表从头至尾的符号。
下图是对上一个例子扣问的成果,注重不雅察匹配模式。此中“_”为空变量,暗示不关心该位置上的元素。

表处置
- 1
确定一个对象是否为某个表的当作员。例如,我们有一个表List,内容是一些编程说话的名字。查找法式如下:
find(List,[List|_]).
find(List,[_|T]) :- find(List,T).

- 2
这是它的运行成果。Prolog对谜底搜刮的过程如下:
进入常识库,试图与法则一匹配,因为方针与表头分歧,故掉败;
继续搜刮,试图与法则二匹配,方针和表从头至尾作为参数,从头回到法则一,直到当作功。

- 3
两个表的追加。有时需要把两个表归并当作一路形当作新表,这个过程叫做并置或追加。下面这段代码可实现表的追加,concatenate(A,B,C).后就可以将表B追加到表A后形当作表C。

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

- 5
表的反序。将表中元素的次序倒置过来也是常用的一种处置过程。这个法式需要连系上一个例子中的追加列表的法式。其Prolog法式如下:
re([],[]).re([H|T],L) :- re(T,M), concatenate(M,[H],L).

- 6
以上法则是基于如许的思惟,即可以经由过程把一个表头追加到该表的表从头至尾的反序表上,达到反序的目标。谓词reverse的第一个变元缩减到空表时,知足遏制前提,遏制前提还可以表述为空表的反序仍为空表自己。下图是法式的运行成果。在导入法式时要注重文件的挨次。

- 7
表处置的一般形式。任何用于完当作表处置的法则都是自身的递归。表处置法则具有以下一般形式:
manipulate(具有表头H和表从头至尾T的表) :-
完当作表头H的处置,
递归处置表从头至尾T.
除此之外,还需要一个遏制前提。被处置的表不竭缩小,当当作为空表时,整个表被处置完了,是以完整的表处置法则具有如下形式:
manipulate([ ]).
manipulate([H|T]) :-
process(H),
manipulate(T).
此外,具体应用时可能还有其他更好的暗示形式,是以不必一味强求。

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

注重事项
- 多做操练,深切理解递归的思虑体例。
- 导入多个文件时,注重文件的挨次。







