我有以下prolog代码。链接谓词是指包含各种链接的另一个文件,例如:
link(b,brown,j)
我正在使用成员谓词来尝试控制此路由程序中的循环。我的想法是,如果我之前到过某个位置,程序将不会尝试沿着这条路走下去。
但是,当我尝试跟踪程序以查看它出错的位置时,当它检查位置是否是位置列表中的成员时,第一个位置已经在列表中,因此程序总是尝试另一个在那之后的路线,它不应该。任何人都知道如何解决这个问题?
member(X,[X|_]).
member(X,[_|Xs]):- member(X,Xs).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
\+member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]),
!.
答案 0 :(得分:3)
首先是一些小的评论:你根本不需要这样做。如果您确实希望将谓词限制为一个答案,请使用once/1
在顶部进行操作。这不仅在概念上更清洁,而且效率更高。
你遇到的另一个问题与Prolog的不安全否定有关。如果你不小心像往常一样交出一个过于笼统的目标,否则总是会失败。换句话说:Prolog中的否定就是破裂。有两种方法:要么为这种情况产生错误,要么只使用更好的定义,如non_member/2
。
让我们看看non_member/2
到底会发生什么:
link(b,brown,j).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
% \+member([Y,Colour],Positions),
non_member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]).
non_member(E, Es) :-
maplist(dif(E), Es).
| ?- route(X,Y,Path,Rs).
Y = X, Path = [X]
; X = b, Y = j, Path = "bj", Rs = []
; X = b, Y = j, Path = "bj", Rs = [_A],
dif([j,brown],_A)
; X = b, Y = j, Path = "bj", Rs = [_A,_B],
dif([j,brown],_A),
dif([j,brown],_B)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C],
dif([j,brown],_A),
dif([j,brown],_B),
dif([j,brown],_C)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D],
dif([j,brown],_A),
dif([j,brown],_B),
dif([j,brown],_C),
dif([j,brown],_D)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D,_E],
dif([j,brown],_A),
dif([j,brown],_B),
dif([j,brown],_C),
dif([j,brown],_D),
dif([j,brown],_E)
; ...
因此,所有答案都描述相同的Path = "bj"
([b,j]
的简称)。但现在最后一个参数是一个元素列表,它们必须与[j,brown]
不同。所以最好的是:
route(X, Y, Path) :-
route(X, Y, Path, []).
以下是重用path/4
的替代定义。我不太确定这些颜色是什么意思。尽管如此:
clink(X-_, Y-Color) :-
link(X, Color, Y).
route(X, Y, Path) :-
path(clink, Path, X-none, Y-_).
甚至更短时间使用library(lambda)
:
route(X, Y, Path) :-
path(\ (Xl,_)^(Yl^C)^clink(Xl,C,Yl), Path, X-none, Y-_).