?- произв( А, В, 8).
А = 1
В = 8;
А = 2
В = 4;
...
Здесь следует сделать одно замечание, относящееся к стилю программирования. Приведенные примеры показали некоторые явно полезные применения assert
и retract
. Однако использование этих отношений требует особой внимательности. Не рекомендуется применять их слишком часто и без должной осторожности - это плохой стиль программирования. Ведь добавляя и удаляя предложения, мы фактически изменяем программу. Поэтому отношения, выполнявшиеся в некоторой ее точке, могут оказаться неверными в другой. В разные моменты времени ответы на одни и те же вопросы будут различными. Таким образом, большое количество обращений к assert
и retract
может затемнить смысл программы и станет трудно разобрать, что истинно, а что — нет. В результате поведение программы может стать непонятным, трудно объяснимым, и вряд ли можно будет ей доверять.
Упражнения
7.6.
(а) Напишите вопрос к пролог-системе, который удаляет из базы данных всю таблицу произв
.
(b) Измените этот вопрос так, чтобы он удалил из таблицы только те строки, в которых произведение равно 0.
7.7. Определите отношение
копия( Терм, Копия)
которое порождает такую копию Терм
'а Копия
, в которой все переменные переименованы. Это легко сделать, используя assert
и retract
.
К настоящему моменту мы познакомились с большинством дополнительных средств управления, за исключением repeat
(повторение). Здесь мы для полноты приводим список всех таких средств.
• отсечение , записывается как ' !
', предотвращает перебор, введено в гл. 5.
• fail
— цель, которая всегда терпит неудачу.
• true
— цель, которая всегда успешна.
• not( P)
— вид отрицания, который всегда ведет себя в точном соответствии со следующим определением:
not( P) :- P, !, fail; true.
Некоторые проблемы, связанные с отсечением и not
детально обсуждались в гл. 5.
• саll( P)
активизирует цель P
. Обращение к саll
имеет успех, если имеет успех P.
• repeat
— цель, которая всегда успешна. Ее особое свойство состоит в том, что она недетерминирована, поэтому всякий раз, как до нее доходит перебор, она порождает новую ветвь вычислений. Цель repeat
ведет себя так, как если бы она была определена следующим образом:
repeat.
repeat :- repeat.
Стандартный способ применения repeat
показан в процедуре квадраты
, которая читает последовательность чисел и выдает их квадраты. Последовательность чисел заканчивается атомом стоп
, который служит для процедуры сигналом окончания работы.
квадраты :-
repeat,
read( X),
( X = стоп, !;
Y is X*X, write( Y), fail ).
7.6. bagof , setof и findall
При помощи механизма автоматического перебора можно получить одни за другим все объекты, удовлетворяющие некоторой цели. Всякий раз, как порождается новое решение, предыдущее пропадает и становится с этого момента недоступным. Однако у нас может возникнуть желание получить доступ ко всем порожденным объектам сразу, например собрав их в список. Встроенные предикаты bagof
(набор) и setof
(множество) обеспечивают такую возможность; вместо них иногда используют предикат findall
(найти все).
Цель
bagof( X, P, L)
порождает список L всех объектов X, удовлетворяющих цели P. Обычно bagof
имеет смысл применять только тогда, когда X и P содержат общие переменные. Например, допустим, что мы включили в программу следующую группу предложений для разбиения букв (из некоторого множества) на два класса — гласные и согласные:
класс( а, глас).
класс( b, согл).
класс( с, согл).
класс( d, согл).
класс( e, глас).
класс( f, согл).
Тогда мы можем получить список всех согласных, упомянутых в этих предложениях, при помощи цели:
?- bagof( Буква, класс( Буква, согл), Буквы).
Буквы = [d, c, d, f]
Если же мы в указанной цели оставим класс букв неопределенным, то, используя автоматический перебор, получим два списка букв, каждый из которых соответствует одному из классов:
?- bagof( Буква, класс( Буква, Класс), Буквы).
Класс = глас
Буквы = [а,e]
Класс = согл
Буквы = [b, c, d, f]
Если bagof( X, P, L)
не находит ни одного решения для P
, то цель bagof
просто терпит неуспех. Если один и тот же X найден многократно, то все его экземпляры будут занесены в L
, что приведет к появлению в L
повторяющихся элементов.
Читать дальше