【问题标题】:Can't understand why is prolog looping infinitly无法理解为什么 prolog 无限循环
【发布时间】:2018-09-14 20:51:10
【问题描述】:

来自 Bratko 的书,Prolog Programming for Artificial Intelligence (4th Edition) 我们有以下代码不起作用 -

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

在本书第 55 页的图 2.15 中,显示parent(Y,Z) 一直在调用,直到堆栈内存不足。

我不明白的是 prolog 首先对 anc4(X,Y) 进行递归调用,而不是对父级 (Y,Z) 进行递归调用。为什么 prolog 不一遍遍地翻到第一行 anc4(X,Y),而是翻到第二行?

您能否详细说明为什么一直调用parent(Y,Z) 行?

谢谢。

【问题讨论】:

  • anc4(X, Z) :- anc4(X, Y), ... 就在那里。 Prolog 将继续选择第一个子句,直到它失败或成功。它也没有。它只是再次调用anc4/2。
  • 请参阅failure-slice,了解如何诊断此类问题。
  • 请参阅this question 了解定义它的一般方法。

标签: recursion prolog transitive-closure


【解决方案1】:

“问题”(即目标顺序)的根源深深植根于语言的基础。

Prolog基于简单高效的时序回溯策略,实现SLD resolution,左递归子句,如anc4/2,导致无限递归。 事实上,逗号运算符(,)/2 代表

如果左表达式成立,仅评估右表达式

因此,子句中的目标顺序实际上是程序的重要组成部分。

对于您的具体情况,

... , parent(Y,Z).

如果

不能调用
anc4(X,Y), 

不成立。

goals order的对应物是clauses order。

即子句交换后整个程序的语义不同:

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

为了更好地理解问题,我认为也值得尝试这个定义。

【讨论】:

    【解决方案2】:

    没有制表机制,Prolog默认不能处理左递归。只有一些 Prolog 系统支持表,通常你需要显式声明哪些谓词是表的。

    如果您正在使用例如XSB、YAP 或 SWI-Prolog,请尝试在包含 anc4/2 谓词定义的源文件顶部添加以下指令:

    :- table(anc4/2).
    

    然后重试您的查询。制表机制检测查询何时调用自身的 variant (*) 并暂停该分支的执行,直到找到查询答案并尝试替代分支(在您的情况下由第二个子句提供) .如果发生这种情况,则使用该答案恢复执行。

    (*) 这里的变体意味着在变量重命名时两个项相等。

    【讨论】:

    • 嗨,谢谢,我不确定我是否理解什么是“表机制”,我只是不明白为什么第二个任期的父母在打电话。
    • 用简短/有限的表格解释编辑了我的答案。如需全面的描述,请参阅支持制表的系统手册。
    • @Alan,table 基本上是在 Prolog 系统中实现 memoization (en.wikipedia.org/wiki/Memoization) 以提高效率。
    • @coder:实际上,制表并不像您的评论听起来那么容易。虽然它有一些便利,但实施它需要(我认为)世界顶级软件工程师之一的几个月,并对正在发生的事情有深刻的了解。并且使用它需要大量经验,因为 - 就像约束一样 - 它基本上是 leaky abstraction
    • @CapelliC,我完全同意我没有提到在 Prolog 中实现 memoization 的复杂性,实现确实是一个非常复杂的想法,我只是解释了基本思想(例如什么是表格)从来没有说了关于实现的任何事情......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多