На Prolog дан простой набор фактов и правил, но запросы возвращают дублирующие решения — объясните, почему так происходит, и покажите, как переработать правила чтобы избежать дублирования
Коротко: дублирование в Prolog возникает потому, что система возвращает каждое возможное доказательство (каждую альтернативу). Если один и тот же ответ получается разными способами (несколько фактов, несколько родительских связей, несколько путей в графе или перекрывающиеся правила), тот же результат будет выдан несколько раз. Решения: убрать дублирующие правила, сузить генерацию (cut/once) либо собрать уникальные ответы через агрегирующие предикаты. Примеры и способы исправления. 1) Дублирующиеся клаузулы Исходно: p(a). q(X) :- p(X). q(X) :- p(X). Запрос ?- q(X). вернёт X = a дважды (2\text{2}2 доказательства). Исправление: удалить дублирующую клаузулу или объединить: q(X) :- p(X). Если нужно только одно решение — можно использовать cut или once: q_once(X) :- p(X), !. % возвращает первую альтернативу q_once2(X) :- once(p(X)). % аналогично 2) Одинаковые ответы из-за нескольких фактов (например, 2 родителя) Факты: parent(mary, ann). parent(john, ann). parent(mary, bob). parent(john, bob). Правило: sibling(X,Y) :- parent(P,X), parent(P,Y), X \= Y. ?- sibling(ann,bob). вернёт пару дважды (для P = mary и P = john). Решения: - Переработать модель (например, хранить пары parent/child так, чтобы не дублировать источники). - Или собрать уникальные результаты: setof((X,Y), sibling(X,Y), Pairs). % отсортированный уникальный список % или findall((X,Y), sibling(X,Y), L0), sort(L0, L). % remove duplicates 3) Множество путей в графе (несколько путей — одинаковая цель) edge(a,b). edge(a,c). edge(b,d). edge(c,d). path(X,Y) :- edge(X,Y). path(X,Y) :- edge(X,Z), path(Z,Y). ?- path(a,d). вернёт d дважды (через b и через c). Исправления: - Если нужны все уникальные цели — собрать и отсортировать: setof(Y, path(a,Y), Ys). - Для уникальных путей можно использовать проверку посещённых вершин (visited) в определении path, чтобы исключить повторные обходы. Короткое резюме решений: - Удалить/объединить дублирующие правила. - Использовать cut/once, если нужен только первый ответ. - Для получения всех уникальных ответов — использовать setof/3 или findall/3 + sort/2. - При моделировании отношений избегать ненужных источников дублирования (изменить представление фактов или добавить аргументы/условия, которые делают каждое доказательство уникальным). Если пришлёте конкретный кусок кода, покажу точную переработку правил.
Примеры и способы исправления.
1) Дублирующиеся клаузулы
Исходно:
p(a).
q(X) :- p(X).
q(X) :- p(X).
Запрос ?- q(X). вернёт X = a дважды (2\text{2}2 доказательства).
Исправление: удалить дублирующую клаузулу или объединить:
q(X) :- p(X).
Если нужно только одно решение — можно использовать cut или once:
q_once(X) :- p(X), !. % возвращает первую альтернативу
q_once2(X) :- once(p(X)). % аналогично
2) Одинаковые ответы из-за нескольких фактов (например, 2 родителя)
Факты:
parent(mary, ann).
parent(john, ann).
parent(mary, bob).
parent(john, bob).
Правило:
sibling(X,Y) :- parent(P,X), parent(P,Y), X \= Y.
?- sibling(ann,bob). вернёт пару дважды (для P = mary и P = john). Решения:
- Переработать модель (например, хранить пары parent/child так, чтобы не дублировать источники).
- Или собрать уникальные результаты:
setof((X,Y), sibling(X,Y), Pairs). % отсортированный уникальный список
% или
findall((X,Y), sibling(X,Y), L0), sort(L0, L). % remove duplicates
3) Множество путей в графе (несколько путей — одинаковая цель)
edge(a,b). edge(a,c). edge(b,d). edge(c,d).
path(X,Y) :- edge(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y).
?- path(a,d). вернёт d дважды (через b и через c). Исправления:
- Если нужны все уникальные цели — собрать и отсортировать:
setof(Y, path(a,Y), Ys).
- Для уникальных путей можно использовать проверку посещённых вершин (visited) в определении path, чтобы исключить повторные обходы.
Короткое резюме решений:
- Удалить/объединить дублирующие правила.
- Использовать cut/once, если нужен только первый ответ.
- Для получения всех уникальных ответов — использовать setof/3 или findall/3 + sort/2.
- При моделировании отношений избегать ненужных источников дублирования (изменить представление фактов или добавить аргументы/условия, которые делают каждое доказательство уникальным).
Если пришлёте конкретный кусок кода, покажу точную переработку правил.