Membег(Х,[Y | Ys])¬ member(X,Ys).
Member (Х,[X | Xs]).
Цель clause (member (X,YS), Body) имеет два решения: {Ys = [X | Xs},Body = true} и {Ys =[Y | Ys1],Body = member (X.Ys1)}. Отметим, что каждое выполнение унификации приводит к созданию новых копий переменных, входящих в предложение. В терминах металогических примитивов freeze и melt можно сказать, что предложения программы хранятся в замороженном виде. Каждое обращение к предложению clause вызывает размораживание ранее замороженного предложения. Описанный метод обращения является логическим аналогом повторной входимости в традиционном программировании.
Существуют системные предикаты, выполняющие добавление предложений к программе и удаление предложений из программы. Основной предикат для добавления предложений – assert (Clause), он присоединяет предложение Clause в качестве последнего предложения соответствующей процедуры. Например, решение цели assert (отец (аран, лот))? добавляет в программу факт отец. При добавлении правил следует вводить дополнительные скобки, чтобы учесть старшинство термов. Например, синтаксически правильным является выражение assert ((родитель (X, Y) ¬omeu(X,Y))).
Имеется вариант предиката assert, а именно asserta, добавляющий предложение в начало процедуры.
Если аргументу Clause значение не сопоставлено (или если значение аргумента Clause имеет вид Н¬В, а переменной Н значение не сопоставлено), то возникает ошибочная ситуация.
Предикат retract (С) удаляет из программы первое предложение, унифицируемое с С. Заметим, что для удаления правила вида a ¬b,с,d следует задать цель retract ((а¬ С)). Обращение к предикату retract может только пометить удаляемое предложение, а не удалить его физически из программы. Реальное удаление может произойти только при решении вопроса верхнего уровня Пролога. Это объясняется методом реализации предиката и может привести к неправильным действиям в некоторых версиях Пролога.
Добавление предложения замораживает имеющиеся в предложении термы. Удаление того же предложения размораживает новые копии термов. Во многих версиях Пролога это используется в качестве простейшего способа копирования термов. В частности, предикат copy, введенный в гл. 10, может быть задан следующим правилом:
copy(X,Y) ¬asserta($tmp(X)),retract ($tmp(Y)).
При этом предполагается, что функтор $tmp больше нигде в программе не используется.
Предикаты assert и retract вводят в Пролог возможность появления побочных эффектов при программировании. Программы, успешное выполнение которых зависит от побочных эффектов, трудны для чтения, отладки и формального анализа. Поэтому эти предикаты являются до некоторой степени спорными, и в ряде случаев их использование свидетельствует о лености ума или некомпетентности. При программировании следует по возможности реже прибегать к этим предикатам. Многие программы, приведенные в данной книге, могли быть записаны с использованием предикатов assert и retract, но при этом были бы потеряны ясность и эффективность. Более того, по мере совершенствования компиляторов с Пролога неэффективность применения предикатов assert и retract будет становиться все более очевидной.
Однако можно привести логическое обоснование некоторого ограниченного использования предикатов assert и retract. Например, добавление правила оправданно, если уже выяснено, что это правило является логическим следствием программы. Такое добавление не влияет на логическое значение программы, так как не позволяет выводить новые следствия, но может повлиять на эффективности поскольку некоторые следствия теперь могут быть выведены быстрее. Такт использование продемонстрировано в конструкции «лемма», описанной в разд. 12.3
Аналогично удаление правила обоснованно,если правило логически излишне. В этом случае удаление играет роль логической сборки мусора, предназначенной для уменьшения размеров программы.
Укажем некоторые другие примеры законного применения предикатов assert и retract. Одно из них состоит в установке и использовании глобальных переключателей, влияющих на выполнение программы. Это применение будет рассматриваться в разд. 13.2, посвященном программистским трюкам. Другое применение возникает при решении задач, которые по определению требуют модификации программы (например, программа consult в разд. 12.5 и такие метапрограммы, как редакторы).