首先是一些小的 cmets:你根本不需要那个剪辑。如果您真的想将谓词限制为一个答案,请使用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-_).