所以
?- canCall(mary, Person).
工作和终止和
?- canFind(mary, Person).
也可以工作并终止。但不知何故
?- canCall(mary, Person), canFind(mary, Person).
不终止。可能的原因是什么?
所以
?- canCall(mary, Person).
工作和终止和
?- canFind(mary, Person).
也可以工作并终止。但不知何故
?- canCall(mary, Person), canFind(mary, Person).
不终止。可能的原因是什么?
(您的实际意思是:查询单独终止,但有时它们的连接不会终止)
您在这里发现了 Prolog 终止属性的一个非常基本的方面。让我们用下面的纯1程序来看看:
canFind(mary, john).
canCall(mary, bob).
canCall(A, B) :-
canCall(B, A).
?- canCall(mary, Person).
Person = bob
; ...
?- canFind(mary, Person).
Person = john.
一切看起来都很好!让我们签入此代码,以便每个人都可以使用它。现在你倒霉的同事尝试:
?- canCall(mary, Person), canFind(mary, Person).
* LOOPS *
哦不,这个循环!也许我只需要重新排列目标:
?- canFind(mary, Person), canCall(mary, Person).
* LOOPS *
再次!
当然,你也很难过。毕竟,您认真地测试了这段代码。它终止了。还是做到了?
这是 Prolog 中最令人困惑的事情之一:我们在这里(至少)有两个不同的查询终止概念。您测试的那个(有时)称为存在终止。但是,我宁愿建议将其称为简单地找到答案。正如你所经历的那样,它非常脆弱。
如果一个查询不仅找到了答案,而且找到了所有答案并完成了查询,那么这称为通用终止或简单终止。如果 Prolog 程序员说查询终止,他们的意思是它普遍终止。
那么我们如何观察普遍终止呢?只需询问所有答案。在 GNU-Prolog 中,您键入a. 在其他系统中,您将不得不锤击SPACE或;Return直到完成,否则您疲劳的眼睛或腕管会阻止它。
?- canCall(mary, Person).
Person = bob
; Person = bob
; Person = bob
; Person = bob
; Person = bob
; ...
所以在这里我们看到有无限多的答案(实际上,我们有限的存在必须证明这一点,但暂时相信我)。
没有更便宜的方法来观察这一点吗?没有所有这些答案文字的墙壁?您可以通过添加一个永远不会成立的条件来“关闭”答案,false
.
所以改为问:
?- canCall(mary, Person), false。
这种查询的结果是什么?永远不可能true
。它只能是false
, 如果它终止。因此,对于这个查询,我们只测试程序的终止属性。
现在,两个(普遍)终止查询的结合将始终终止。所以这种终止方式更加健壮。
通用端接还有许多很酷的特性。例如,您可以随意交换子句的顺序(即事实和规则):无论它们的顺序如何,所有程序都共享完全相同的终止属性。
另一个是您可以在failure-slice的帮助下轻松找到程序中未终止的来源。从这个开始阅读。
在面向命令的编程语言中,这个概念并不容易出现。但是,对于迭代器,您有非常相似的概念:如果迭代器产生第一个项目,则对应于存在终止;如果产生了有限多个项目,也就是说,如果在有限多个之后next
完成,则对应于通用终止。有点儿。
1 实际上,在不纯程序中,您有各种荒谬的行为。所以考虑它们是没有意义的。
我想,当您单独运行时,Person
会统一为两个不同的值。检查这个。