В процессе диалога с машиной вывода Prolog следующее найденное решение можно получить передав символ ;. в данном редакторе в поле ввода нужно поставить ; на следующей строчке в поле ввода и заново запустить вывод, нажав на кнопку Run it [F8]. Таким образом, если поле ввода будет выглядеть следующим образом:
query(X).
;
;
то ответом системы будет
X = pamela X = tom false.
В первый раз будет найден результат pamela, во второй раз tom, в третий раз новое решение найдено не будет и пролог ответит false.
Часто в задаче требуется найти все возможные решения не в процессе диалога с системой, а непосредственно в процессе вывода. В таком случае используется один из встроенных предикатов bagof, setof или findall.
Предикат bagof(X, P, L) формирует список L, состоящий из всех объектов X, для которых P истинно. То есть, если в данном примере спросить
bagof(GParent, grandparent(GParent, patricia), Result).
ответом будет
Result = [pamela, tom].
Но если не указывать точное значение patricia, то Prolog будет находить все пары решений и формировать соответствующие списки. На вопрос
bagof(GParent, grandparent(GParent, Child), Result).
;
;
Получим ответ
Child = ann,
Result = [pamela, tom] Child = jim,
Result = [bob] Child = patricia,
Result = [pamela, tom].
в SWI-Prolog этот же ответ будет более нагляден:
?- bagof(GParent, grandparent(GParent, Child), Result).
Child = ann,
Result = [pamela, tom];
Child = jim,
Result = [bob];
Child = patricia,
Result = [pamela, tom].
Предикат setof аналогичен bagof, но результирующий список будет упорядочен и не будет содержать дубликаты, если они есть. Немного изменим исходный пример, чтобы увидеть разницу между ними (поменяем местами первые два предиката):
parent(tom, bob).
parent(pamela, bob).
parent(tom, liz).
parent(bob, ann).
parent(bob, patricia).
parent(patricia, jim).
grandparent(X, Y) :- parent(X, Z), parent(Z, Y).
тогда
bagof(GParent, grandparent(GParent, Child), Result).
;
;
выводит результат
Child = ann,
Result = [tom, pamela] Child = jim,
Result = [bob] Child = patricia,
Result = [tom, pamela].
в первом списке tom и pamela расположены не в алфавитном порядке, но
setof(GParent, grandparent(GParent, Child), Result).
;
;
выводит
Child = ann,
Result = [pamela, tom] Child = jim,
Result = [bob] Child = patricia,
Result = [pamela, tom].
Предикат findall(X, P, L) формирует список L из всех X, для которых может быть выведена цель P. при этом список L может содержать дубликаты. Запрос
findall(GParent, grandparent(GParent, Child), Result).
на исходном примере из вопроса выведет
Result = [pamela, pamela, tom, tom, bob].
если вместо переменной Child задать точное значение, то разницы между bagof и findall нет (SWI-Prolog, в интерпретаторе retexter, нужно удалить приглашение ?-)
?- findall(GParent, grandparent(GParent, patricia), Result).
Result = [pamela, tom].
Если нужно получить список, эквивалентный списку L предиката findall, но не содержащий повторяющиеся элементы, можно воспользоваться операцией ^ в предикате setof(X, P, L). данная операция сообщает Prolog, что нас не интересует значение одной из переменных, входящих в состав цели P (SWI-Prolog, в интерпретаторе retexter, нужно удалить приглашение ?-):
?- setof(GParent, Child ^ grandparent(GParent, Child), Result).
Result = [bob, pamela, tom].