Given following facts:
route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...
I am required to find all the pairs of tube Lines that do not have any stations in common, producing the following:
| ?- disjointed_lines(Ls).
Ls = [(yellow,blue),(yellow,green),(yellow,red),(yellow,silver)] ? ;
no
I came up with the below answer, however it does not only give me incorrect answer, but it also does not apply my X^ condition - i.e. it still prints results per member of Stations lists separately:
disjointed_lines(Ls) :-
route(W, Stations1),
route(Z, Stations2),
setof(
(W,Z),X^
(member(X, Stations1),nonmember(X, Stations2)),
Ls).
This is the output that the definition produces:
| ?- disjointed_lines(L).
L = [(green,green)] ? ;
L = [(green,blue)] ? ;
L = [(green,silver)] ? ;
...
I believe that my logic relating to membership is incorrect, however I cannot figure out what is wrong. Can anyone see where am I failing?
I also read Learn Prolog Now chapter 11 on results gathering as suggested here, however it seems that I am still unable to use the ^ operator correctly. Any help would be appreciated!
UPDATE:
As suggested by user CapelliC, I changed the code into the following:
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).
The following, however, gives me duplicates of (X,Y) and (Y,X), but the next step will be to remove those in a separate rule. Thank you for the help!
I think you should put route/2 calls inside setof' goal, and express disjointness more clearly, so you can test it separately. About the ^
operator, it requests a variable to be universally quantified in goal scope. Maybe a concise explanation like that found at bagof/3 manual page will help...
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'