Prolog 谓词无终止

Prolog 谓词无终止,prolog,failure-slice,transitive-closure,Prolog,Failure Slice,Transitive Closure,我有一些关于黑白顶点图的程序: black(root). black(v1). black(v3). black(v4). edge(root,root). edge(v1,root). edge(v2,v1). edge(v3,v1). edge(v4,v3). edge(v5,v2). edge(v5,v4). edge(v6,v5). vertex(X) :- edge(X,_). vertex(X) :- edge(_,X). white(X) :- vertex(X),

我有一些关于黑白顶点图的程序:

black(root).
black(v1).
black(v3).
black(v4).

edge(root,root).
edge(v1,root).
edge(v2,v1).
edge(v3,v1).
edge(v4,v3).
edge(v5,v2).
edge(v5,v4).
edge(v6,v5).

vertex(X) :- edge(X,_).
vertex(X) :- edge(_,X).

white(X) :-
   vertex(X),
   not(black(X)).

foo(root).
foo(X) :-
   edge(X,Y),
   black(Y),
   foo(Y).
当我运行目标
foo(X)
时,我遇到了一个问题: 如果我删除事实
边(根,根)
程序会找到一些解决方案(6种不同的解决方案)。否则,我得到无限解,所有解都是
X=root

为什么会发生这种情况?

首先是一个快速的答案,它向您展示了Prolog程序员是如何看待您的程序的,下面是对它的解释。您的程序不会终止,因为以下情况不会终止:

black(root). black(v1) :- false. black(v3) :- false. black(v4) :- false. edge(root,root). edge(v1,root) :- false. edge(v2,v1) :- false. edge(v3,v1) :- false. edge(v4,v3) :- false. edge(v5,v2) :- false. edge(v5,v4) :- false. edge(v6,v5) :- false. foo(root) :- false. foo(X) :- X = root, Y = root, edge(X,Y), black(Y), foo(Y), false. 现在了解详情

在回答你的问题之前,让我们后退一步。我们首先需要找到一个观察问题的好方法。目标
foo(X)
确实产生了答案,实际上只有
X=root
。所以,也许你只是迫不及待地等待序言的结束?通过询问查询
foo(X),false
,我们摆脱了这些恼人的、让人目不转睛的答案,我们将等待得到
false
作为回答

我们仍然不能确定程序的非终止属性。但是我们可以通过插入目标
false
(以及
(=)/2
)来缩小实际原因。在上面的故障片中,我插入了最大值。如果您刚刚开始,只需添加一个false,然后重新加载程序并重试查询。有了一些经验,您将很快能够快速识别此类零件。所以现在我们只需要理解

foo(root) :- edge(root,root), % always true black(root), % always true foo(root), false. foo(root):- 边(根,根),%始终为真 黑色(根),%始终为真 foo(root),false。 甚至更短

foo(root) :- foo(root). foo(root):- foo(根)。 Prolog非常简单但高效的执行机制不会检测到这样的循环。基本上有几种解决方法:

  • 手动添加循环检测。这通常非常容易出错

  • 使用-见上文

  • 编写自己的元解释器来检测循环

  • 使用B-Prolog或XSB Prolog中提供的类似tabling的语言扩展


  • 这个答案确实需要投票表决。 foo(root) :- foo(root).