Prolog(Sicstus)-非成员和一组问题



给定以下事实:

route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...

我被要求找到所有没有任何公共站点的管道对,产生以下内容:

| ?- disjointed_lines(Ls).
Ls = [(yellow,blue),(yellow,green),(yellow,red),(yellow,silver)] ? ;
no

我得出了以下答案,但它不仅给了我错误的答案,而且也不适用于我的X^条件,即它仍然单独打印每个站点列表成员的结果:

disjointed_lines(Ls) :- 
route(W, Stations1),
route(Z, Stations2),
setof(
(W,Z),X^
(member(X, Stations1),nonmember(X, Stations2)),
Ls).

这是定义产生的输出:

| ?- disjointed_lines(L).
L = [(green,green)] ? ;
L = [(green,blue)] ? ;
L = [(green,silver)] ? ;
...

我认为我关于成员资格的逻辑是不正确的,但我不知道错在哪里。有人能看到我在哪里失败吗?

我还阅读了"立即学习Prolog"第11章关于这里建议的结果收集,但似乎我仍然无法正确使用^运算符。任何帮助都将不胜感激!


更新:

根据用户CapelliC的建议,我将代码更改为以下内容:

disjointed_lines(Ls) :- 
setof(
(W,Z),(Stations1, Stations2)^
((route(W, Stations1),
route(Z, Stations2),notMembers(Stations1,Stations2))),
Ls).
notMembers([],_).
notMembers([H|T],L):- notMembers(T,L), nonmember(H,L).

但是,下面给出了(X,Y)和(Y,X)的重复项,但下一步将在单独的规则中删除它们。谢谢你的帮助!

我认为您应该将route/2调用放在目标集内,并更清楚地表达不相交,这样您就可以单独测试它了。关于^运算符,它要求在目标范围内对变量进行通用量化。也许在bagof/3手册页上找到一个简洁的解释会有所帮助。。。

disjointed_lines(Ls) :- 
setof((W,Z), Stations1^Stations2^(
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2)
), Ls).
disjoint(Stations1, Stations2) :-
... % could be easy as intersection(Stations1, Stations2, [])
% or something more efficient: early fail at first shared 'station'

setof/3如果您创建了一个辅助谓词来表达您感兴趣的关系,则更容易使用:

disjoint_routes(W, Z) :-
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2).

这样,disjointed_lines/1的定义变得更短、更简单,并且不再需要任何^运算符:

disjointed_lines(Ls) :-
setof((W, Z), disjoint_routes(W, Z), Ls).

setof/3结果中不需要的变量会自动隐藏在辅助谓词定义中。

最新更新