Prolog间接关系

标签 prolog

我刚刚开始学习 Prolog 并面临一个有线问题:

假设有人排两队等待:

left(a,b).
left(c,i).
left(i,j).
right(k,j).

代表这样的线:

line1:a,b  line2: c,i,j,k.

我想要看看这些人中是否有任何人是同一阵营的。我写的内容遵循以下规则:

nextto(X,Y):- left(X,Y);left(Y,X);right(X,Y);right(Y,X).
sameline(X,Y):- nextto(X,Y).
sameline(X,Y):- nextto(X,Z),sameline(Z,Y).

我将人与人之间的“左/右”关系转换为“nextto”关系。 当两个人实际上在同一行时,代码可以正常工作。但如果我尝试:

?- sameline(a,c)

其中“a”和“c”不在同一行。程序进入无限循环,直到耗尽本地堆栈。我假设它一直尝试在“X”和“Y”之间查找变量“Z”,如果找不到,程序将创建另一个“Z”来继续搜索。我见过使用递归调用的典型祖先示例:

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

这是有道理的。但是我的代码与祖先示例有何不同?显然 nextto(a,j) 会返回 false,但为什么循环不会停止?

这是我学习 Prolog 的第二天,所以 Prolog 的高级使用可能没有帮助:(。

谢谢。

最佳答案

如果你跟踪:

?- sameline(a,c).

你会看到它陷入了循环a <-> b由于:

nextto(X,Y):- left(X,Y);left(Y,X);right(X,Y);right(Y,X).

在上面的规则中,您让 next(a,b)next(b,a)成功,但你只需要一次就能成功,以免陷入循环:

在跟踪中你可以看到:

Redo: (8) sameline(a, c) ? creep    %OK trying to succeed sameline(a,c)
   Call: (9) nextto(a, _884) ? creep

上面继续:

Call: (10) left(a, _884) ? creep
   Exit: (10) left(a, b) ? creep     %Only b succeeds left(a,_)
   Exit: (9) nextto(a, b) ? creep
   Call: (9) sameline(b, c) ? creep  %OK trying to succeed recursively 

同一行(b,c)。

但这最终会调用:

Redo: (9) sameline(b, c) ? creep
   Call: (10) nextto(b, _884) ? creep
   Call: (11) left(b, _884) ? creep
   Fail: (11) left(b, _884) ? creep
   Redo: (10) nextto(b, _884) ? creep
   Call: (11) left(_882, b) ? creep
   Exit: (11) left(a, b) ? creep
   Exit: (10) nextto(b, a) ? creep
   Call: (10) sameline(a, c) ? creep   % Same thing we began due to cycle

为了解决这个问题,如果我正确理解你想要做什么,你应该定义:

nextto(X,Y):- left(X,Y);right(Y,X).
sameline(X,Y):- nextto(X,Y).
sameline(X,Y):- nextto(X,Z),sameline(Z,Y).

nextto/2 的定义强制遵循一条路径而不陷入循环。

示例:

?- sameline(c,X).
X = i ;
X = j ;
X = k ;
false.

?- sameline(c,i).
true ;
false.

?- sameline(a,c).
false.

编辑

如果您希望 nextto/2 处理循环,解决该问题的一种方法是保留您访问过的内容的列表:

sameline(X,Y):- sameline(X,Y,[X]).

nextto(X,Y):- left(X,Y);left(Y,X);right(X,Y);right(Y,X).
sameline(X,Y,_):- nextto(X,Y).
sameline(X,Y,L):- nextto(X,Z),\+member(Z,L),sameline(Z,Y,[Z|L]).

关于Prolog间接关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46895625/

相关文章:

prolog - 列表上的成对关系

Prolog - 使用 DCG 处理二进制数据

prolog - 只查找列表中的数字

reflection - SWI Prolog 中的变量名

prolog - 为什么这个斐波那契程序的动态版本比另一个程序快得令人难以置信? Prolog解决方案

prolog - 如何在文件中使用 op/3

list - Prolog 中的元素处理问题,但不在常规列表中?

prolog - 从列表中删除元素

list - 如何在 Prolog 中执行列表的长串联?

Prolog:如何判断谓词是否是确定性的