Prolog - 关系


关系是我们在 Prolog 中必须适当提及的主要特征之一。这些关系可以表达为事实和规则。之后我们将了解家庭关系,如何在 Prolog 中表达基于家庭的关系,以及家庭的递归关系。

我们将通过创建事实和规则来创建知识库,并对它们进行查询。

Prolog 中的关系

在Prolog程序中,它指定了对象和对象的属性之间的关系。

假设有一条语句“Amit 有一辆自行车”,那么我们实际上是在声明两个对象之间的所有权关系——一个是 Amit,另一个是自行车。

如果我们问一个问题,“阿米特有自行车吗?”,我们实际上是在试图找出一种关系。

关系有很多种,其中有些也可以是规则。即使关系没有明确定义为事实,规则也可以找出关系。

我们可以定义兄弟关系如下 -

两个人是兄弟,如果,

  • 他们都是男性。

  • 他们有同一个父母。

现在考虑我们有以下短语 -

  • 父母(sudip,piyus)。

  • 父母(sudip,raj)。

  • 男(piyus)。

  • 男(拉吉)。

  • 兄弟(X,Y):-父母(Z,X),父母(Z,Y),男性(X),男性(Y)

这些子句可以给我们答案:piyus 和 raj 是兄弟,但这里我们将得到三对输出。它们是:(piyus,piyus),(piyus,raj),(raj,raj)。对于这些对,给定的条件是正确的,但是对于(piyus,piyus),(raj,raj)这对,他们实际上不是兄弟,他们是同一个人。因此,我们必须正确地创建子句才能形成关系。

修改后的关系如下 -

A 和 B 是兄弟,如果 -

  • A和B均为男性

  • 他们有同一个父亲

  • 他们有同一个母亲

  • A和B不一样

Prolog 中的家庭关系

在这里我们将看到家庭关系。这是可以使用 Prolog 形成复杂关系的示例。我们想要制作一个家谱,并将其映射为事实和规则,然后我们可以对它们运行一些查询。

假设家谱如下 -

家庭关系

从这棵树上,我们可以了解到,关系很少。这里鲍勃是帕姆和汤姆的孩子,鲍勃还有两个孩子——安和帕特。鲍勃有一个兄弟莉兹,他的父母也是汤姆。所以我们想要做出如下谓词 -

谓词

  • 父母(帕姆,鲍勃)。

  • 父母(汤姆,鲍勃)。

  • 父母(汤姆,莉兹)。

  • 父母(鲍勃,安)。

  • 父母(鲍勃,帕特)。

  • 父母(帕特,吉姆)。

  • 父母(鲍勃,彼得)。

  • 父母(彼得,吉姆)。

从我们的例子中,它有助于说明一些重要的观点 -

  • 我们根据家谱中给定的信息声明对象的 n 元组来定义父关系。

  • 用户可以轻松地向Prolog系统查询程序中定义的关系。

  • Prolog 程序由以句号终止的子句组成。

  • 关系的参数可以(除其他外)是:具体对象,或常量(例如 pat 和 jim),或一般对象,例如 X 和 Y。我们程序中的第一类对象称为Atomics。第二类对象称为变量。

  • 对系统的问题包含一个或多个目标。

有些事实可以用两种不同的方式来写,例如家庭成员的性别可以用任何一种形式来写 -

  • 女性(帕姆)。

  • 男(汤姆)。

  • 男(鲍勃)。

  • 女(莉兹)。

  • 女(拍拍)。

  • 女(安)。

  • 男(吉姆)。

或者采用下面的形式 -

  • 性别(pam,女性)。

  • 性别(汤姆,男性)。

  • 性别(鲍勃,男性)。

  • … 等等。

现在,如果我们想建立母亲和姐妹的关系,那么我们可以写如下 -

母亲和姐妹的关系

在 Prolog 语法中,我们可以写 -

  • 母亲(X,Y):-父母(X,Y),女性(X)。

  • 姐妹(X,Y):- 父母(Z,X),父母(Z,Y),女性(X),X \== Y。

现在让我们看看实际演示 -

知识库 (family.pl)

female(pam).
female(liz).
female(pat).
female(ann).
male(jim).
male(bob).
male(tom).
male(peter).
parent(pam,bob).
parent(tom,bob).
parent(tom,liz).
parent(bob,ann).
parent(bob,pat).
parent(pat,jim).
parent(bob,peter).
parent(peter,jim).
mother(X,Y):- parent(X,Y),female(X).
father(X,Y):- parent(X,Y),male(X).
haschild(X):- parent(X,_).
sister(X,Y):- parent(Z,X),parent(Z,Y),female(X),X\==Y.
brother(X,Y):-parent(Z,X),parent(Z,Y),male(X),X\==Y.

输出

| ?- [family].
compiling D:/TP Prolog/Sample_Codes/family.pl for byte code...
D:/TP Prolog/Sample_Codes/family.pl compiled, 23 lines read - 3088 bytes written, 9 ms

yes
| ?- parent(X,jim).

X = pat ? ;

X = peter

yes
| ?-
mother(X,Y).

X = pam
Y = bob ? ;

X = pat
Y = jim ? ;

no
| ?- haschild(X).

X = pam ? ;

X = tom ? ;

X = tom ? ;

X = bob ? ;

X = bob ? ;

X = pat ? ;

X = bob ? ;

X = peter

yes
| ?- sister(X,Y).

X = liz
Y = bob ? ;

X = ann
Y = pat ? ;

X = ann
Y = peter ? ;

X = pat
Y = ann ? ;

X = pat
Y = peter ? ;

(16 ms) no
| ?-

现在让我们看看我们可以从以前的家庭关系中建立更多的关系。因此,如果我们想建立祖父母关系,可以如下形成 -

祖父母

我们还可以创建一些其他关系,如妻子、叔叔等。我们可以将这些关系写成如下 -

  • 祖父母(X,Y):- 父母(X,Z),父母(Z,Y)。

  • 祖母(X,Z):-母亲(X,Y),父母(Y,Z)。

  • 祖父(X,Z):-父亲(X,Y),父母(Y,Z)。

  • 妻子(X,Y):-父母(X,Z),父母(Y,Z),女性(X),男性(Y)。

  • 叔叔(X,Z):-兄弟(X,Y),父母(Y,Z)。

那么让我们编写一个 prolog 程序来看看它的实际效果。在这里我们还将看到跟踪执行情况的跟踪。

知识库 (family_ext.pl)

female(pam).
female(liz).
female(pat).
female(ann).

male(jim).
male(bob).
male(tom).
male(peter).

parent(pam,bob).
parent(tom,bob).
parent(tom,liz).
parent(bob,ann).

parent(bob,pat).
parent(pat,jim).
parent(bob,peter).
parent(peter,jim).

mother(X,Y):- parent(X,Y),female(X).
father(X,Y):-parent(X,Y),male(X).
sister(X,Y):-parent(Z,X),parent(Z,Y),female(X),X\==Y.
brother(X,Y):-parent(Z,X),parent(Z,Y),male(X),X\==Y.
grandparent(X,Y):-parent(X,Z),parent(Z,Y).
grandmother(X,Z):-mother(X,Y),parent(Y,Z).
grandfather(X,Z):-father(X,Y),parent(Y,Z).
wife(X,Y):-parent(X,Z),parent(Y,Z),female(X),male(Y).
uncle(X,Z):-brother(X,Y),parent(Y,Z).

输出

| ?- [family_ext].
compiling D:/TP Prolog/Sample_Codes/family_ext.pl for byte code...
D:/TP Prolog/Sample_Codes/family_ext.pl compiled, 27 lines read - 4646 bytes written, 10 ms

| ?- uncle(X,Y).

X = peter
Y = jim ? ;

no
| ?- grandparent(X,Y).

X = pam
Y = ann ? ;

X = pam
Y = pat ? ;

X = pam
Y = peter ? ;

X = tom
Y = ann ? ;

X = tom
Y = pat ? ;

X = tom
Y = peter ? ;

X = bob
Y = jim ? ;

X = bob
Y = jim ? ;

no
| ?- wife(X,Y).

X = pam
Y = tom ? ;

X = pat
Y = peter ? ;

(15 ms) no
| ?-

跟踪输出

在 Prolog 中我们可以跟踪执行情况。要跟踪输出,您必须输入“trace.”进入跟踪模式。然后从输出中我们可以看到我们只是在追踪“pam is mother of who?”。通过将 X = pam 和 Y 作为变量来查看跟踪输出,其中 Y 将是 bob 作为答案。要退出跟踪模式,请按“notrace”。

程序

| ?- [family_ext].
compiling D:/TP Prolog/Sample_Codes/family_ext.pl for byte code...
D:/TP Prolog/Sample_Codes/family_ext.pl compiled, 27 lines read - 4646 bytes written, 10 ms

(16 ms) yes
| ?- mother(X,Y).

X = pam
Y = bob ? ;

X = pat
Y = jim ? ;

no
| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- mother(pam,Y).
   1 1 Call: mother(pam,_23) ?
   2 2 Call: parent(pam,_23) ?
   2 2 Exit: parent(pam,bob) ?
   3 2 Call: female(pam) ?
   3 2 Exit: female(pam) ?
   1 1 Exit: mother(pam,bob) ?
   
Y = bob

(16 ms) yes
{trace}
| ?- notrace.
The debugger is switched off

yes
| ?-

家庭关系中的递归

在上一节中,我们已经看到我们可以定义一些家庭关系。这些关系本质上是静态的。我们还可以创建一些递归关系,可以用下图来表达 -

家庭关系中的递归 家庭关系中的递归1

所以我们可以理解,前驱关系是递归的。我们可以使用以下语法来表达这种关系 -

predecessor(X, Z) :- parent(X, Z).
predecessor(X, Z) :- parent(X, Y),predecessor(Y, Z).

现在让我们看看实际演示。

知识库 (family_rec.pl)

female(pam).
female(liz).
female(pat).
female(ann).

male(jim).
male(bob).
male(tom).
male(peter).

parent(pam,bob).
parent(tom,bob).
parent(tom,liz).
parent(bob,ann).
parent(bob,pat).
parent(pat,jim).
parent(bob,peter).
parent(peter,jim).

predecessor(X, Z) :- parent(X, Z).
predecessor(X, Z) :- parent(X, Y),predecessor(Y, Z).

输出

| ?- [family_rec].
compiling D:/TP Prolog/Sample_Codes/family_rec.pl for byte code...
D:/TP Prolog/Sample_Codes/family_rec.pl compiled, 21 lines read - 1851 bytes written, 14 ms

yes
| ?- predecessor(peter,X).

X = jim ? ;

no
| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- predecessor(bob,X).
   1 1 Call: predecessor(bob,_23) ?
   2 2 Call: parent(bob,_23) ?
   2 2 Exit: parent(bob,ann) ?
   1 1 Exit: predecessor(bob,ann) ?
   
X = ann ? ;
   1 1 Redo: predecessor(bob,ann) ?
   2 2 Redo: parent(bob,ann) ?
   2 2 Exit: parent(bob,pat) ?
   1 1 Exit: predecessor(bob,pat) ?
   
X = pat ? ;
   1 1 Redo: predecessor(bob,pat) ?
   2 2 Redo: parent(bob,pat) ?
   2 2 Exit: parent(bob,peter) ?
   1 1 Exit: predecessor(bob,peter) ?
   
X = peter ? ;
   1 1 Redo: predecessor(bob,peter) ?
   2 2 Call: parent(bob,_92) ?
   2 2 Exit: parent(bob,ann) ?
   3 2 Call: predecessor(ann,_23) ?
   4 3 Call: parent(ann,_23) ?
   4 3 Fail: parent(ann,_23) ?
   4 3 Call: parent(ann,_141) ?
   4 3 Fail: parent(ann,_129) ?
   3 2 Fail: predecessor(ann,_23) ?
   2 2 Redo: parent(bob,ann) ?
   2 2 Exit: parent(bob,pat) ?
   3 2 Call: predecessor(pat,_23) ?
   4 3 Call: parent(pat,_23) ?
   4 3 Exit: parent(pat,jim) ?
   3 2 Exit: predecessor(pat,jim) ?
   1 1 Exit: predecessor(bob,jim) ?
   
X = jim ? ;
   1 1 Redo: predecessor(bob,jim) ?
   3 2 Redo: predecessor(pat,jim) ?
   4 3 Call: parent(pat,_141) ?
   4 3 Exit: parent(pat,jim) ?
   5 3 Call: predecessor(jim,_23) ?
   6 4 Call: parent(jim,_23) ?
   6 4 Fail: parent(jim,_23) ?
   6 4 Call: parent(jim,_190) ?
   6 4 Fail: parent(jim,_178) ?
   5 3 Fail: predecessor(jim,_23) ?
   3 2 Fail: predecessor(pat,_23) ?
   2 2 Redo: parent(bob,pat) ?
   2 2 Exit: parent(bob,peter) ?
   3 2 Call: predecessor(peter,_23) ?
   4 3 Call: parent(peter,_23) ?
   4 3 Exit: parent(peter,jim) ?
   3 2 Exit: predecessor(peter,jim) ?
   1 1 Exit: predecessor(bob,jim) ?
   
X = jim ?

(78 ms) yes
{trace}
| ?-