недоступным. Однако у нас может возникнуть желание получить доступ ко всем порожденным объектам сразу, например собрав их в список. Встроенные предикаты bagof (набор) и setof (множество) обеспечивают такую возможность; вместо них иногда используют предикат findall (найти все).
Цель
bagof( X, P, L)
порождает список L всех объектов X, удовлетворяющих цели Р. Обычно bagof имеет смысл применять только тогда, когда Х и Р содержат общие переменные. Например, допустим, что мы включили в программу следующую группу предложений для разбиения букв (из некоторого множества) на два класса - гласные и согласные:
класс( а, глас).
класс( b, согл).
класс( с, согл).
класс( d, согл).
класс( е, глас).
класс( f, согл).
Тогда мы можем получить список всех согласных, упомянутых в этих предложениях, при помощи цели:
?- bagof( Буква, класс( Буква, согл), Буквы).
Буквы = [d, c, d, f]
Если же мы в указанной цели оставим класс букв неопределенным, то, используя автоматический перебор, получим два списка букв, каждый из которых соответствует одному из классов:
?- bagof( Буква, класс( Буква, Класс), Буквы).
Класс = глас
Буквы = [а,е]
Класс = согл
Буквы = [b, c, d, f]
Если 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 тем, что собирает в список