Пролог (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)] ? ;
...

Я считаю, что моя логика в отношении членства неверна, однако я не могу понять, что не так. Может ли кто-нибудь увидеть, в чем я ошибаюсь?

Я также прочитал главу 11 Learn Prolog Now о сборе результатов, как было предложено здесь , однако мне кажется, что я все еще не могу правильно использовать оператор ^. Любая помощь будет оценена по достоинству!


ОБНОВЛЕНИЕ:

По предложению пользователя 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), но следующим шагом будет удаление их в отдельном правиле. Спасибо вам за помощь!


person qwerty    schedule 08.01.2017    source источник


Ответы (2)


Я думаю, вы должны поместить вызовы route / 2 в setof 'target и более четко выразить несвязанность, чтобы вы могли протестировать ее отдельно. Что касается оператора ^, он запрашивает универсальную количественную оценку переменной в области цели. Возможно, краткое объяснение, подобное тому, которое можно найти в руководстве 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'
person CapelliC    schedule 08.01.2017
comment
Большое спасибо! Я добавил следующее определение, чтобы исправить проблему, следуя вашему предложению: notMembers ([], _). notMembers ([H | T], L): - notMembers (T, L), не член (H, L). Полное решение дает мне дубликаты [(X, Y), (Y, X)], поэтому удаление этих дубликатов будет для меня последним шагом :) - person qwerty; 08.01.2017
comment
Чтобы удалить дубликаты, вы можете использовать W @< Z в качестве дополнительной цели в своем setof вызове. - person Isabelle Newbie; 10.01.2017

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, автоматически скрываются внутри определения вспомогательного предиката.

person Isabelle Newbie    schedule 08.01.2017
comment
Большое вам спасибо, это отличный совет! Обязательно воспользуюсь, если еще будут проблемы с ^ :) - person qwerty; 08.01.2017