超出Prolog路由规划器中的本地堆栈错误

时间:2015-12-13 14:04:49

标签: list recursion prolog

我正在尝试在城镇之间编写Prolog路线规划器。这是我的代码:

road(meath,dublin,5). 
road(dublin,kildare,9).
road(kildare,wicklow,7).
road(wicklow,wexford,10).

/*Rules:*/
route(X,Y,[H|_ ],N) :-
   road(H,Y,_),
   routen(X,Y,N1),
   N is N1.
route(X,Y,[H|T],N) :-
   road(X,H,_ ),
   routen(X,Y,N1), 
   N is N1,
   route(H,Y,T,_),
   !.
route(X,Y,[],N) :-
   road(X,Y,N1),
   N is N1.

routen(X,Y,N) :-
   road(X,Y,N).
routen(X,Y,N) :-
   road(X,Z,N1),
   road(Z,Y,N2),
   N is N1+N2.
routen(X,Y,N) :-
   routen(X,Z,N1),
   routen(Z,Y,N2),
   N is N1+N2,
   !.

谓词road有两个城镇和它们之间的距离。规则route查找XY之间的城镇列表,routen找到两个城镇之间的总距离。

当我运行route时,它有时会运行,有时我会运行ERROR: Out of local stack

示例:

?- route(meath,wexford,[dublin,kildare,wicklow],31).
true. 

?- route(meath,wexford,[dublin,kildare,wicklow],30).
false.

?- route(meath,kerry,[dublin,kildare,wicklow],31).
ERROR: Out of local stack

最后一个应返回false,因为meathkerry之间的路由不存在。有谁知道我为什么会收到错误?

1 个答案:

答案 0 :(得分:1)

Prolog中的规则是左递归的。 在你最后一条规则中你做了:

routen(X,Y,N) :- routen(X,Z,N1),routen(Z,Y,N2),N is N1+N2,!.

它使你的程序尝试规则 routen(X,Z,N1)无限次。这意味着在一个点上堆栈将是满的。

发生了什么:

  1. 找到从米斯到凯瑞的路线。

  2. 它确实存在于城市之间的直接道路:试图寻找另一个中间城市。它找到了meath-dublin。

  3. 然后尝试都柏林 - 克里。但是,再次,它确实存在于城市之间的直接道路:试图寻找另一个中间城市。它找到都柏林 - 基尔代尔。等等。

  4. 最后它到了找micklow-wexford。所以到目前为止找到的路线是:meath-dublin-kildare-wicklow-wexford。

  5. 现在尝试使用第一个

    的wexford-kerry
    route(X,Y,[H|_ ],N) :- road(H,Y,_),routen(X,Y,N1), N is N1.
    

    满足第一个

    road(H,Y,_)
    

    然后减少

    routen(X,Y,N1), N is N1.
    

    5.1尝试使用第一条规则

    routen(wexford,kerry,N) :- road(wexford,kerry,N).
    

    失败了,因为它们之间没有直接的道路。所以它叫:

    routen(wexford,kerry,N) :- road(wexford,Z,N1),road(Z,kerry,N2),N is N1+N2.
    

    失败导致它无法满足

    road(wexford,Z,N1).
    

    最后,它尝试使用最后一条规则

    routen(wexford,kerry,N) :- routen(wexford,Z,N1),routen(Z,kerry,N2),N is N1+N2,!.
    

    所以它减少了

    routen(wexford,Z,N1),routen(Z,kerry,N2),N is N1+N2,!.
    
  6. 它试图满足第一个

    routen(wexford,Z,N1).
    

    routen(X,Y,N) :- road(X,Y,N).
    routen(X,Y,N) :- road(X,Z,N1),road(Z,Y,N2),N is N1+N2.
    routen(X,Y,N) :- routen(X,Z,N1),routen(Z,Y,N2),N is N1+N2,!.
    

    分别与

    X=wexford
    Z=DG51_  % or something like that. That is, an not instantiated variable
    

    并重复步骤5.1

  7. 正如你所看到的,它永远不会找到这个城市" kerry"并且它处于无限循环中。

    这里是新代码:

    road(meath,dublin,5). 
    road(dublin,kildare,9).
    road(kildare,wicklow,7).
    road(wicklow,wexford,10).
    
    /*Rules:*/
    
    route(X,Y,[H|_ ],N) :- routen(X,Y,N),!.
    %route(X,Y,[H|T],N) :- road(X,H,_ ),routen(X,Y,N1), N is N1, route(H,Y,T,_).
    route(X,Y,[],N) :- road(X,Y,N1), N is N1.
    routen(X,Y,N) :- road(X,Y,N).
    %routen(X,Y,N) :- road(X,Z,N1),road(Z,Y,N2),N is N1+N2.
    routen(X,Y,N) :- road(X,Z,N1),routen(Z,Y,N2),N is N1+N2.
    

    请注意,在我放的最后一条规则

    road(X,Z,N1)
    

    routen(Z,Y,N2)
    

    所以,如果那个主体的第一个条款失败了,你就永远不会陷入第二个循环。