Prolog子句单独终止,但不一起终止

abs*_*ted 2 prolog terminate non-termination failure-slice

所以

?- canCall(mary, Person).
Run Code Online (Sandbox Code Playgroud)

工作并终止,

?- canFind(mary, Person).
Run Code Online (Sandbox Code Playgroud)

也可以工作并终止。但是不知何故

?- canCall(mary, Person), canFind(mary, Person). 
Run Code Online (Sandbox Code Playgroud)

不终止。可能是什么原因?

fal*_*lse 5

(您实际上的意思是:查询会个别终止,但有时它们的连词不会终止)

您在这里发现了Prolog端接属性的一个非常基本的方面。让我们用下面的纯1程序看一下:

canFind(mary, john).

canCall(mary, bob).
canCall(A, B) :-
   canCall(B, A).

?- canCall(mary, Person).
   Person = bob
;  ... 

?- canFind(mary, Person).
   Person = john.
Run Code Online (Sandbox Code Playgroud)

一切都很好!让我们签入此代码,以便每个人都可以使用它。现在,您不幸的同事尝试:

?- canCall(mary, Person), canFind(mary, Person).
* LOOPS *
Run Code Online (Sandbox Code Playgroud)

哦,不,这循环了!也许我只需要重新排列目标:

?- canFind(mary, Person), canCall(mary, Person).
* LOOPS *
Run Code Online (Sandbox Code Playgroud)

再次!

当然,你也心烦意乱。毕竟,您已经认真测试了此代码。它终止了。还是呢?

终止的两个概念

这是Prolog中最令人困惑的事情之一:在这里(至少)有两个不同的查询终止概念。您测试的一个(有时)称为存在终止。但是,我宁可建议将其称为查找答案。如您所见,它非常脆。

并且,如果查询不仅找到答案,还找到所有答案并完成查询,则这称为通用终止或简称终止。如果Prolog程序员说查询终止,则表示该查询普遍终止。

那么我们如何观察通用终止呢?只需索取所有答案。在GNU-Prolog中,键入a。在其他系统中,您将不得不锤击SPACE;Return直到完成,否则您疲倦的眼睛或腕管会阻止它。

?- canCall(mary, Person).
   Person = bob
;  Person = bob
;  Person = bob
;  Person = bob
;  Person = bob
;  ...
Run Code Online (Sandbox Code Playgroud)

因此,在这里我们看到有无限多个答案(实际上,我们有限的生物必须证明这一点,但暂时要相信我)。

有没有便宜的方法可以观察到这一点?没有答案的墙吗?您可以通过添加永远不会成立的条件来“关闭”答案false

因此,请问:

?-canCall(mary,Person),false

这样查询的结果是什么?永远不可能true。它只能是false,应该终止。因此,与此查询我们简单地测试程序的终止性质

现在,两个(通用)终止查询的结合将始终终止。因此,这种终止更加健壮。

通用终端还有许多其他很酷的特性。例如,您可以根据需要交换子句的顺序(即事实和规则):不管子句的顺序如何,所有程序都共享完全相同的终止属性。

另一个是,您可以借助轻松地在程序中找到不终止的来源。开始阅读这一本

在面向命令的编程语言中,这个概念并不容易出现。但是,对于迭代器,您有非常相似的概念:如果迭代器产生第一个项目,则该项目将对应于存在终止;如果产生了有限的多个项目,即,如果在有限的多个项目next完成之后,则将对应于通用终止。的种类。


1实际上,在不纯正的程序中,您有各种各样的荒谬行为。因此,考虑它们是没有意义的。