我正在尝试在城镇之间编写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
查找X
和Y
之间的城镇列表,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
,因为meath
和kerry
之间的路由不存在。有谁知道我为什么会收到错误?
答案 0 :(得分:1)
Prolog中的规则是左递归的。 在你最后一条规则中你做了:
routen(X,Y,N) :- routen(X,Z,N1),routen(Z,Y,N2),N is N1+N2,!.
它使你的程序尝试规则 routen(X,Z,N1)无限次。这意味着在一个点上堆栈将是满的。
发生了什么:
找到从米斯到凯瑞的路线。
它确实存在于城市之间的直接道路:试图寻找另一个中间城市。它找到了meath-dublin。
然后尝试都柏林 - 克里。但是,再次,它确实存在于城市之间的直接道路:试图寻找另一个中间城市。它找到都柏林 - 基尔代尔。等等。
最后它到了找micklow-wexford。所以到目前为止找到的路线是:meath-dublin-kildare-wicklow-wexford。
现在尝试使用第一个
的wexford-kerryroute(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,!.
它试图满足第一个
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
正如你所看到的,它永远不会找到这个城市" 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)
所以,如果那个主体的第一个条款失败了,你就永远不会陷入第二个循环。