На Prolog дан простой набор фактов и правил, но запросы возвращают дублирующие решения — объясните, почему так происходит, и покажите, как переработать правила чтобы избежать дублирования

24 Ноя в 12:16
1 +1
0
Ответы
1
Коротко: дублирование в 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.
- При моделировании отношений избегать ненужных источников дублирования (изменить представление фактов или добавить аргументы/условия, которые делают каждое доказательство уникальным).
Если пришлёте конкретный кусок кода, покажу точную переработку правил.
24 Ноя в 12:25
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир