ЗАДАНИЕ 6.2

Внесем данные о том, что Хромов оплатил взнос и просмотрим

содержание всей базы и отдельно список должников, а затем исключим всех,кто не уплатил взнос, выполнив запросы:

 

?-запись_об_уплате(член('Хромов',40)),выдать_сведения(_).

?-выдать_сведения(член(_,_,не_уплачено)).

?-сократить_состав(член(_,_,не_уплачено)),выдать_сведения(_).

 

Предикат выдать_сведения/1 пример применения вынуждаемого возврата для получения всех возможных вариантов согласования цели. При этом результат, выводимый на экран, уничтожается механизмом возвратов из памяти программы, но его можно накапливать, используя побочный эффект действия предикатов assert/1 и retract/1. Это накопление реализуется процедурами действия над счетчиком:

 

установить_счетчик(Имя,Начало):-

retractall(счетчик(Имя,_)),

assert(счетчик(Имя,Начало)).

 

увеличить_счетчик(Имя,Прирост):-

retract(счетчик(Имя,Значение)),

Новое_значение is Значение+Прирост,

assert(счетчик(Имя,Новое_значение)).

 

сбросить_счетчик(Имя,Значение):-

retract(счетчик(Имя,Значение)).

 

Для иллюстрации рассмотрим процедуру, подсчитывающую число членов клуба:

 

подсчет_членов(член(Фамилия,Возраст,Данные_об_уплате),_):-

установить_счетчик(число_членов,0),

член(Фамилия,Возраст,Данные_об_уплате),

увеличить_счетчик(число_членов,1),

fail.

подсчет_членов(_,Счетчик):-

сбросить_счетчик(число_членов,Счетчик).

 

Если программа предназначена для получения ряда значений при помощи одного из встроенных предикатов чтения входных данных, то такой подход использовать уже нельзя, так как read/1 и другие читают новое значение только при первом вызове и не делают этого при возврате. Эту трудность можно преодолеть, добавив в программу определение предиката repeat/0 - согласуемого всегда, в том числе и при возвратах:

 

repeat.

repeat:-repeat.

 

Используем этот прием для определения процедуры меню:

 

меню:-repeat,

nl,nl,write(' МЕНЮ'),nl,

write('1. Сведения о членах клуба.'),nl,

write('2. Посчитать количество членов.'),nl,

write('3. Добавить запись о члене клуба.'),nl,

write('0. ВЫХОД'),nl,nl,

write('Введите номер пункта меню '),

read(Х),

обработать(Х).

 

Предикат обработать/1 предназначен для организации остановки или повторения соответственно сделанному поьзователем выбору:

 

обработать(0):-!.

обработать(Х):-пункт(Х),fail.

 

пункт/1 выполняет соответствующую операцию

 

пункт(1):-nl,write('Состав клуба:'),

nl,выдать_сведения(_),!.

пункт(2):-nl,подсчет_членов(член(_,_,_),Число),

write('Количество членов клуба = '),

write(Число),nl,!.

пункт(3):-nl,write('Введите данные нового члена клуба '),nl,

write('Фамилия '),read(Фамилия),

write('Возраст '),read(Возраст),

write('Отметка об уплате взноса '),read(Данные_об_уплате),

пополнить_состав(член(Фамилия,Возраст,Данные_об_уплате)),!.

пункт(_):-write('Такой пункт неопределен!'),nl,!.