Глава 4. Пункт 1 Назад | Содержание | Вперёд

Глава 4 ИСПОЛЬЗОВАНИЕ СТРУКТУР:

ПРИМЕРЫ Структуры данных вместе с сопоставлением, автоматическими возвратами и арифметикой представляют собой мощный инструмент программирования. В этой главе мы расширим навыки использования этого инструмента при помощи следующих учебных программных примеров: получение структурированной информации из базы данных, моделирование недетерминированного автомата, планирование маршрута поездки и решение задачи о расстановке восьми ферзей на шахматной доске. Мы увидим также, как в Прологе реализуется принцип абстракции данных.

double_line(); 4. 1.    Получение структурированной информации из базы данных Это упражнение развивает навыки представления структурных объектов данных и управления ими. Оно показывает также, что Пролог является естественным языком запросов к базе данных.

База данных может быть представлена на Прологе в виде множества фактов. Например, в базе данных о семьях каждая семья может описываться одним предложением. На рис. 4.1 показано, как информацию о каждой семье можно представить в виде структуры. Каждая семья состоит из трех компонент: мужа, жены и детей. Поскольку количество детей в разных семьях может быть разным, то их целесообразно представить в виде списка, состоящего из произвольного числа элементов. Каждого члена семьи в свою очередь можно представить структурой, состоящей из

Рис. 4. 1.   Структурированная информация о семье.

четырех компонент: имени, фамилии, даты рождения и работы. Информация о работе - это либо "не работает", либо указание места работа и оклада (дохода). Информацию о семье, изображенной на рис. 4.1, можно занести в базу данных с помощью предложения:

        семья( членсемьи( том, фокс, дата( 7, май, 1950),

              работает( bbс, 15200) ),

              членсемьи( энн, фокс, дата( 9, май, 1951), неработает),

              [членсемьи( пат, фокс, дата( 5, май, 1973), неработает),

              членсемьи( джим, фокс, дата( 5, май, 1973), неработает) ] ).

Тогда база данных будет состоять из последовательности фактов, подобных этому, и описывать все семьи, представляющие интерес для нашей программы.

В действительности Пролог очень удобен для извлечения необходимой информации из такой базы данных. Здесь хорошо то, что можно ссылаться на объекты, не указывая в деталях всех их компонент. Можно задавать только структуру интересующих нас объектов и оставлять конкретные компоненты без точного описания или лишь с частичным описанием. На рис. 4.2 приведено несколько примеров. Так, а запросах к базе данных можно ссылаться на всех Армстронгов с помощью терма

        семья( членсемьи( _, армстронг, _, _ ), _, _ )

Символы подчеркивания обозначают различные анонимные переменные, значения которых нас не заботят. Далее можно сослаться на все семьи с тремя детьми при помощи терма:

        семья( _, _, [ _, _, _ ])

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

        ?-  семья( _, членсемьи( Имя, Фамилия, _, _ ), [ _, _, _ | _ ]).

Главным моментом в этих примерах является то, что указывать интересующие нас объекты можно не только по их содержимому, но и по их структуре. Мы задаем одну структуру и оставляем ее аргументы в виде слотов (пропусков).

Рис. 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, при помощи вопроса:

        ?-  семья( Муж, Жена, Дети),

             общий( [ Муж, Жена | Дети], Доход),

             длина( [ Муж, Жена | Дети], N),

             Доход/N < 2000.

Упражнения 4. 1.    Напишите вопросы для поиска в базе данных о семьях.

(а)        семей без детей;

(b)        всех работающих детей;

(с)        семей, где жена работает, а муж нет,

(d)        всех детей, разница в возрасте родителей которых составляет не менее 15 лет.

Посмотреть ответ

4. 2.    Определите отношение

        близнецы( Ребенок1, Ребенок2)

для поиска всех близнецов в базе данных о семьях.

Посмотреть ответ

Назад | Содержание | Вперёд

hl();

Соседние файлы в папке Программирование на языке Пролог для искусственного интеллекта