Prolog (Sicstus) - 非成员和 setof 问题
Prolog (Sicstus) - nonmember and setof issues
鉴于以下事实:
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^ 条件 - 即它仍然单独打印 Stations 列表的每个成员的结果:
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)] ? ;
...
我认为我关于会员资格的逻辑不正确,但我无法弄清楚哪里出了问题。谁能看到我哪里失败了?
我也按照建议阅读了 Learn Prolog Now 第 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调用放在setof'目标里面,表达不相交更清楚,这样你就可以单独测试了。关于^
运算符,它要求一个变量在目标范围内被普遍量化。也许像 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
结果中不需要的变量会自动隐藏在辅助谓词定义中。
鉴于以下事实:
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^ 条件 - 即它仍然单独打印 Stations 列表的每个成员的结果:
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)] ? ;
...
我认为我关于会员资格的逻辑不正确,但我无法弄清楚哪里出了问题。谁能看到我哪里失败了?
我也按照建议阅读了 Learn Prolog Now 第 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调用放在setof'目标里面,表达不相交更清楚,这样你就可以单独测试了。关于^
运算符,它要求一个变量在目标范围内被普遍量化。也许像 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
结果中不需要的变量会自动隐藏在辅助谓词定义中。