【问题标题】:Why does my prolog rule get stuck in infinite recursion为什么我的序言规则陷入无限递归
【发布时间】:2020-12-01 22:05:58
【问题描述】:

我的代码可以达到预期目的,但最后总是卡在一个循环中,给我一个错误,提示“超出堆栈限制”。我的代码如下:

byCar(auckland,hamilton).
byCar(hamilton,raglan).
byCar(valmont,saarbruecken).
byCar(valmont,metz).
   
byTrain(metz,frankfurt).
byTrain(saarbruecken,frankfurt).
byTrain(metz,paris).
byTrain(saarbruecken,paris).
   
byPlane(frankfurt,bangkok).
byPlane(frankfurt,singapore).
byPlane(paris,losAngeles).
byPlane(bangkok,auckland).
byPlane(singapore,auckland).
byPlane(losAngeles,auckland).


travel(X,Y):- byCar(X,Y).
travel(X,Y):- byTrain(X,Y).
travel(X,Y):- byPlane(X,Y).
travel(X,Y):- travel(X,Z), travel(Z,Y).

【问题讨论】:

  • byAny(X,Y) :- byCar(X,Y) ; byTrain(X,Y) ; byPlane(X, Y). travel(X,Y) :- closure(byAny,X,Y).thisclosure/3
  • 请参阅this 以了解为什么它会循环。

标签: recursion prolog transitive-closure failure-slice


【解决方案1】:

当你调用travel(metz, To)之类的东西时,travel/2 的最后一个子句将调用 travel(metz, Z) 并带有一个新变量 Z,然后它可以调用 travel(metz, Z2) 并带有一个新变量 Z2,依此类推.

这个问题被称为“左递归”:你有一个递归调用,它等效于原始目标一直到子句的“左侧”(即开头)。解决方案是在递归调用之前“取得一些进展”。在这种情况下,您可以在递归之前移动一跳:

step(X, Y) :-
    byCar(X, Y).
step(X, Y) :-
    byTrain(X, Y).
step(X, Y) :-
    byPlane(X, Y).

travel(X, Y) :-
    step(X, Y).
travel(X, Z) :-
    step(X, Y),
    travel(Y, Z).

现在结束:

?- travel(metz, To).
To = frankfurt ;
To = paris ;
To = bangkok ;
To = singapore ;
To = auckland ;
To = hamilton ;
To = raglan ;
To = auckland ;
To = hamilton ;
To = raglan ;
To = losAngeles ;
To = auckland ;
To = hamilton ;
To = raglan ;
false.

正如false 的评论中所指出的,您可以使用通用谓词来捕获这种闭包:Definition of Reflexive Transitive Closure。或者,一些 Prolog 系统提供了一种称为“表格”的功能,您可以使用它来避免此类问题:https://www.swi-prolog.org/pldoc/man?section=tabling-non-termination

【讨论】:

  • 另一种方法是添加一个参数来跟踪您看过的地点并检查(使用member/2)列表中是否有新位置。教科书中有很多这样的例子。
  • 我不认为这是“另一种”方法。无论如何,您不需要以基本相同的方式解决左递归问题吗?如果您可以发布替代答案,那就太好了!
  • 如果您将travel(X,Y):- travel(X,Z), travel(Z,Y). 更改为travel(X,Seen0, Seen, Y):- \+ member(X, Seen), travel(X,[X|Seen], Seen1, Z), travel(Z,[Z|Seen1], Seen,Y).,那么我认为它可以工作(尚未测试)。制表要容易得多。 ;) 当然,如果您定义 travel0(X,Y) :- byCar(X,Y). 等,您也可以将该行更改为 travel(X,Y):- travel0(X,Z), travel(Z,Y).(本质上,查询分层是手动完成的)
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2022-09-28
  • 1970-01-01
  • 1970-01-01
  • 2016-04-08
  • 2015-03-11
  • 1970-01-01
相关资源
最近更新 更多