您的谓词几乎可以工作。只有两个问题和一些我想解决的细节。首先,将具有不同参数的谓词分开会极大地提高可读性。所以让我们把 path/5 的一个规则放在 path/6 的两个规则前面,如下所示:
path(X,Y,[X|Cs], S, P) :-
path(X,Y,[X],Cs, S, P),
P is S+W. % <-(1)
path(X,X,_,[], S, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited),
path(Z,Y,[Z|Visited],Cs, S+W, P). % <-(2)
查看您的示例查询 path/5 似乎是您要调用以查找路径的谓词。在其单一规则的第二个目标(标记为% <-(1)
)中,您使用的是内置 is/2 和S+W
右侧的表达式。该变量W
首次出现在此处,因此未绑定。这会导致实例化错误,如下例所示:
?- X is 1+W.
ERROR!!
INSTANTIATION ERROR- in arithmetic: expected bound value
但是,由于您只使用 path/5 来调用 path/6 ,因此不需要该目标。其次,在 path/6 的第二条规则中,在最后一个目标中,您将S+W
作为参数传递而不是首先对其进行评估。要查看会发生什么,让我们% <-(1)
从 path/5 中删除标记的目标,并将示例图添加到您的代码中:
connection(ori,a,2).
connection(a,b,5).
connection(b,a,4).
connection(b,dest,1).
现在考虑您的示例查询,还有一个额外的目标:
?- path(ori, dest, X, 0, P), Weight is P.
P = 0+2+5+1,
Weight = 8,
X = [ori,a,b,dest] ? ;
no
如您所见,该参数S+W
导致最终权重是表达式而不是值。考虑在递归目标之前添加一个目标并作为参数S1 is S+W
传递。S1
第三,您在谓词 notIn/2 中使用了内置 (\==)/2。这种比较成功或失败,没有副作用或统一。这很好,只要两个参数都绑定到值,但与未绑定的变量一起使用时会出现问题。考虑以下查询:
?- X=Y, X\==Y.
no
按预期失败,但是:
?- X\==Y, X=Y.
X = Y
成功因为X\==Y
对变量没有影响,所以可以在下一个目标中统一它们。改用 dif/2 是个好主意:
?- X=Y, dif(X,Y).
no
?- dif(X,Y), X=Y.
no
最后,有两个小建议:首先,由于您使用 path/5 的第四个参数0
作为权重的起始值,您不妨在规则的单一目标中这样做,从而简化与路径的接口/4。其次,最好为谓词提供一个更具描述性的名称,以反映其声明性,例如 start_end_path_weight/4。所以你的代码看起来像这样:
notIn(A,[]).
notIn(A,[H|T]):-
dif(A,H),
notIn(A,T).
start_end_path_weight(X,Y,[X|Cs], P) :-
path(X,Y,[X],Cs, 0, P).
path(X,X,_,[], P, P).
path(X,Y,Visited,[Z|Cs], S, P) :-
connection(X,Z,W),
notIn(Z,Visited),
S1 is S+W,
path(Z,Y,[Z|Visited],Cs, S1, P).
通过这些修改,您的示例查询如下所示:
?- start_end_path_weight(ori,dest,X,W).
W = 8,
X = [ori,a,b,dest] ? ;
no