Если bagof( X, Р, L) не находит ни одного решения для Р, то цель bagof
просто терпит неуспех. Если один и тот же Х найден многократно, то все его экземпляры будут занесены в L, что приведет к появлению в L
повторяющихся элементов.
Предикат setof работает аналогично предикату bagof. Цель
setof( X, P, L)
как и раньше, порождает список L объектов X, удовлетворяющих Р. Только на этот раз список L будет упорядочен, а из всех повторяющихся элементов, если таковые есть, в него попадет только один. Упорядочение происходит по алфавиту или по отношению '<', если элементы списка - числа. Если элементы списка - структуры, то они упорядочиваются по своим главным функторам. Если же главные функторы совпадают, то решение о порядке таких термов принимается по их первым несовпадающим функторам, расположенным выше и левее других (по дереву). На вид объектов, собираемых в список, ограничения нет. Поэтому можно, например, составить список пар вида
Класс / Буква
при этом гласные будут расположены в списке первыми ("глас" по алфавиту раньше "согл"):
?- setof( Класс/Буква, класс( Буква, Класс), Спис).
Спис = [глас/а, глас/е, согл/b, согл/с, согл/d, согл/f]
Еще одним предикатом этого семейства, аналогичным bagof, является findall.
findall( X, P, L)
тоже порождает список объектов, удовлетворяющих Р. Он отличается от bagof
тем, что собирает в список все объекты X, не обращая внимание на (возможно) отличающиеся для них конкретизации тех переменных из P, которых нет в X. Это различие видно из следующего примера:
?- findall( Буква, класс( Буква, Класс), Буквы).
Буквы= [a, b, c, d, e, f]
Если не существует ни одного объекта X, удовлетворяющего P, то findall все равно имеет успех и выдает L = [ ].