printЛогическое программирование

printПредикаты порождения

Мы можем получить все решения для некоторой цели одно за другим с помощью перебора, но при получении нового решения предыдущее становится недоступным. Предикаты порождения позволяют получить доступ ко всем решениям сразу, собирая их в список.
Предикат bagof(X,P,L) порождает список L всех объектов X, удовлетворяющих цели P. X и P должны содержать общие переменные. Если нет ни одного решения, то согласование цели завершается неудачей. Если один и тот же X найден многократно, то все его экземпляры будут в списке.
класс(a,глас).
класс(b,согл). 
класс(с,согл).
класс(d,согл).
класс(e,глас). 
класс(f,согл).
?-bagof(X,класс(X,согл),L).
L=[b,c,d,f]
Если цель будет содержать другие неконкретизированные переменные, то для каждой из возможных конкретизаций этих переменных получается свой список решений:
?-bagof(X,класс(X,Kласс),L).
Класс=глас, L=[a,e];
Класс=согл, L=[b,c,d,f];
no
Предикат setof(X,P,L) работает аналогично bagof, но список L упорядочен и не содержит повторяющихся элементов.
?-setof(Kласс/X,класс(X,Kласс),L).
L=[глас/a,глас/e,согл/b,согл/c,согл/d,согл/f]
Предикат findall(X,P,L) отличается от предиката bagof тем, что собирает в список L все объекты X, удовлетворяющие цели P, не обращая внимания на конкретизации тех переменных, которых нет в X. Если не существует ни одного решения, то цель findall(X,P,L) все равно успешна и L=[].
?-findall(X,класс(X,Kласс),L).
L=[a,b,c,d,e,f]
Предикаты порождения можно определить, используя предикаты assertz и retract:
:-dynamic(нашли/1).
findall(X,P,L):-P,assertz(нашли(X)),fail; собрать(L).
собрать([X|L]):-retract(нашли(X)),!,собрать(L).
собрать([]).
loading