В действительности Пролог очень удобен для
извлечения необходимой информации из такой базы
данных. Здесь хорошо то, что можно ссылаться на
объекты, не указывая в деталях всех их компонент.
Можно задавать только
семья( членсемьи( _, армстронг, _, _ ), _, _ )
Символы подчеркивания обозначают различные анонимные переменные, значения которых нас не заботят. Далее можно сослаться на все семьи с тремя детьми при помощи терма:
семья( _, _, [ _, _, _ ])
Чтобы найти всех замужних женщин, имеющих по крайней мере троих детей, можно задать вопрос:
?- семья( _, членсемьи( Имя, Фамилия, _, _ ), [ _, _, _ | _ ]).
Главным моментом в этих примерах является то, что указывать интересующие нас объекты можно не только по их содержимому, но и по их структуре. Мы задаем одну структуру и оставляем ее аргументы в виде слотов (пропусков).
Рис. 4. 2. Описания объектов по их структурным свойствам: (а) любая семья Армстронгов; (b) любая семья, имеющая ровно трех детей; (с) любая семья, имеющая по крайней мере три ребенка. Структура (с) дает возможность получить имя и фамилию жены конкретизацией переменных Имя и Фамилия.
Можно создать набор процедур, который служил бы утилитой, делающей взаимодействие с нашей базой данных более удобным. Такие процедуры являлись бы частью пользовательского интерфейса. Вот некоторые полезные процедуры для нашей базы данных:
муж( X) :- % X - муж
семья( X, _, _ ).
жена( X) :- % X - жена
семья( _, X, _ ).
ребенок( X) :- % X - ребенок
семья( _, _, Дети),
принадлежит( X, Дети).
принадлежит( X, [X | L ]).
принадлежит( X, [Y | L ]) :-
принадлежит( X, L).
существует( Членсемьи) :-
% Любой член семьи в базе данных
муж( Членсемьи);
жена( Членсемьи);
ребенок( Членсемьи).
дата рождения( Членсемьи( _, _, Дата, _ ), Дата).
доход( Членсемьи( _, _, _, работает( _, S) ), S).
% Доход работающего
доход( Членсемьи( _, _, _, неработает), 0).
% Доход неработающего
Этими процедурами можно воспользоваться, например, в следующих запросах к базе данных:
Найти имена всех людей из базы данных:
?- существует( членсемьи( Имя,Фамилия, _, _ )).
Найти всех детей, родившихся в 1981 году:
?- ребенок( X), датарождения( X, дата( _, _, 1981) ).
Найти всех работающих жен:
?- жена( членсемьи( Имя, Фамилия, _, работает( _, _ ))).
Найти имена и фамилии людей, которые не работают и родились до 1963 года:
?- существует членсемьи( Имя, Фамилия, дата( _, _, Год), неработает) ),
Год < 1963.
Найти людей, родившихся до 1950 года, чей доход меньше, чем 8000:
?- существует( Членсемьи),
датарождения( Членсемьи, дата( _, _, Год) ),
Год < 1950,
доход( Членсемьи, Доход),
Доход < 8000.
Найти фамилии людей, имеющих по крайней мере трех детей:
?- семья( членсемьи( _, Фамилия, _, _ ), _, [ _, _, _ | _ ]).
Для подсчета общего дохода семья полезно определить сумму доходов людей из некоторого списка в виде двухаргументного отношения:
общий( Список_Людей, Сумма_их_доходов)
Это отношение можно запрограммировать так:
общий( [ ], 0). % Пустой список людей
общий( [ Человек | Список], Сумма) :-
доход( Человек, S),
% S - доход первого человека
общий( Список, Остальные),
% Остальные - сумма доходов остальных
Сумма is S + Остальные.
Теперь общие доходы всех семей могут быть найдены с помощью вопроса:
?- семья( Муж, Жена, Дети),
общий( [Муж, Жена | Дети], Доход).
Пусть отношение длина подсчитывает количество элементов списка, как это было определено в разд. 3.4. Тогда мы можем найти все семьи, которые имеют доход на члена семьи, меньший, чем 2000, при помощи вопроса: