【问题标题】:Why do I get a Infinite Loop (Prolog)为什么我得到一个无限循环(Prolog)
【发布时间】:2019-06-03 18:32:40
【问题描述】:

我刚刚开始学习 Prolog,并且一直在玩弄它。现在我到了一个我被卡住的地步。我写的程序在我请求时进入了一个无限循环

?- q(b).

我不明白为什么会这样。如果有人可以向我解释,那就太好了。

p(a).    
p(b).
q(Y) :- r(X), r(Y).    
r(X) :- r(f(X)).    
r(a) :- p(c).    
r(a) :- p(a).    
r(b) :- p(b).

【问题讨论】:

  • 提示:r(something_completely_different) 不会终止也是出于同样的原因。
  • 一般来说,试着想想 Prolog 是如何得出一个事实的:它以当前的目标(例如r(something) 并从上到下遍历规则以找到与其统一的规则头。然后它尝试从左到右推导该规则主体中的每个目标。Prolog 只会在推导第一个目标时尝试推导主体的第二个目标 - 这也称为深度优先搜索。
  • 好的。这意味着程序以“q(Y) :- r(X), r(Y).”开头。之后它要检查“r(X)”并转到“r(X) :- r(f(X)).”。它在那里尝试检查“r(f(x))”。它在“r(X) :- r(f(X)).”中循环。我理解正确吗?
  • 是的,就是这样 :-)

标签: prolog infinite-loop


【解决方案1】:

正如评论中所说,循环是由r/1引起的。要说明原因,请输入 ?- trace, q(b). 查看跟踪(现在忽略单例警告):

 Call:q(b)
 Call:r(_4244)
 Call:r(f(_4162))
 Call:r(f(f(_4162)))
 Call:r(f(f(f(_4162))))
 Call:r(f(f(f(f(_4162)))))
 Call:r(f(f(f(f(f(_4162))))))
 Call:r(f(f(f(f(f(f(_4162)))))))
 Call:r(f(f(f(f(f(f(f(_4162))))))))

现在您可以看到它尝试派生r/1 进入循环。您还可以查看this question 以获得更深入的解释。

请注意,在序言中,子句的顺序很重要。只需尝试将行 r(X) :- r(f(X)). 放在程序的底部。现在尝试?- q(b). 在第一个答案上你得到true,因为prolog 在进入循环之前将X 与a 和Y 与b 统一起来。

【讨论】:

    【解决方案2】:

    确定未终止原因的另一种方法是通过在程序中添加目标false来减少程序执行的推理次数:

    q(Y) :- r(X), false, r(Y).
    
    r(X) :- r(f(X)), false.
    r(a) :- false, p(c).
    r(a) :- false, p(a).
    r(b) :- false, p(b).
    
    ?- q(Y).
    ** LOOPS **

    由于该程序仍在循环中,因此您需要修改可见部分中的某些内容。请注意有多少东西已被完全删除!不管p/1怎么定义,这个问题都会一直存在。

    如果您仔细查看q/1,您会发现其中一个问题:

    q(Y) :- r(X), false, r(Y)。

    变量Y 根本没有用在可见部分。 X 只出现一次。因此,r(X) 可能是最通用的查询,因此它可能具有最差的终止属性(这实际上取决于r/1 的定义)。无论如何,q/1 的参数对终止没有影响!

    还有一个属性可以得出结论:子句的顺序对终止属性没有任何影响!你可以很容易地看到这一点:无论出现在哪里,用 false 完全删除的子句都可以删除。

    欲了解更多信息,请参阅。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 2012-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多