Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие Функциональное и логическое программирование.docx
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
309.57 Кб
Скачать

Выполнение запроса в Прологе.

Работу интерпретатора языка Пролог можно трактовать как рекурсивный циклический процесс унификации (согласования) и вычисления подцелей.

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

После ввода пользователем запроса, запрос активируется, т.е. помещается в вершину стека активных запросов. Интерпретатор приступает к анализу фраз текущей программы в поисках первой фразы, заголовок которой согласуется с запросом. Чтобы запрос согласовался с заголовком фразы, необходимо совпадение у них имени предиката и количества аргументов, причем все аргументы должны согласоваться.

Правила согласования термов:

  1. переменная согласуется с константой или структурой. В результате эта переменная становится конкретизированной, т.е. принимает значение этой константы или структуры;

  2. переменная согласуется с переменной, при этом они обе становятся одной и той же переменной (т.е. интерпретатор дает им одно и то же внутреннее имя);

  3. анонимная переменная "_" согласуется с любым объектом;

  4. константа согласуется с константой, если они идентичны;

  5. структура согласуется с другой структурой, если они имеют одинаковые функторы, а аргументы поддаются унификации.

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

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

При успешном выполнении запроса пользователя интерпретатор выводит на терминал значения всех тех переменных, входящих в состав запроса, которые были конкретизированы в результате процесса обработки, или слово «да», если переменные в запросе отсутствовали.

Если пользователь введет символ «;» после того, как интерпретатор нашел ответ, то это будет эквивалентно отказу от полученного ответа. Интерпретатор вернется назад и попытается найти иной ответ. Покажем процесс выполнения запроса на примере. Допустим, созданы базы данных «отец», «брат» и правило «дядя»:

отец (коля, миша).

отец(коля, саша).

брат(миша, саша).

брат(вася, коля).

дядя(А, В):-

брат(А, С),

отец(С, В).

Рассмотрим запрос «дядя» к программе:

?-дядя(вася, X).

Как только в стеке появился запрос, интерпретатор приступает к поиску множества фраз с тем же самым именем предиката и с тем же количеством аргументов, что и у запроса. Если таких фраз нет, то запрос неудачен. Интерпретатор анализирует первую фразу множества фраз «дядя» и пытается согласовать каждый аргумент запроса с соответствующим аргументом этой фразы. В нашем случае запрос «дядя» успешно согласуется с заголовком правила «дядя». В результате конкретизируется переменная А, которая получает значение «вася», а В и X становятся одной и той же неконкретизированной переменной. После того, как переменная, расположенная в заголовке правила, будет согласована с другим термом, результат согласования распространяется на каждый случай использования этой переменной в правиле.

Состояние интерпретатора:

активные запросы фразы программы

?-дядя(вася, X). дядя(вася, X):-

брат(вася, С),

отец(С, X).

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

Тело правила «дядя» состоит из двух подцелей «брат (вася, С)» и «отец (С, X)». Первая подцель «брат (вася, С)» помещается в стек запросов:

активные запросы фразы программы

?-дядя(вася, X). дядя(вася, X):-

брат(вася, С),

отец(С, X).

?- брат (вася, С).

Теперь новый запрос «брат (вася, С)» является активным запросом. Исходный запрос дядя (вася, X) однако все еще находится в стеке в ожидании обработки тела правила «дядя». Запрос «брат» теперь указывает на начало множества фраз «брат».Если попытка согласования запроса с заголовком фразы закончится неудачей, то интерпретатор перейдет к анализу следующей фразы соответствующего множества. Этот процесс будет продолжаться до тех пор, пока не обнаружится фраза, которую можно будет унифицировать с запросом. Если интерпретатор не найдет такую фразу, то запрос завершится неудачей.

В нашем случае интерпретатор предпринимает попытку согласовать подцель «брат (вася, С)» с фразой «брат (миша, саша)». Эта попытка заканчивается неудачей, т.к. «вася» не согласуется с «миша». Затем интерпретатор переходит к анализу следующей фразы «брат(вася, коля)». В данном случае запрос согласуется с фразой, переменная С конкретизируется, получает значение «коля», которое будет использоваться при каждом употреблении переменной С в правиле «дядя».

Состояние интерпретатора:

активные запросы фразы программы

?-дядя(вася, X). - указывет на - дядя(вася, X):-

брат(вася, коля),

отец(коля, X).

?- брат (вася, коля). - указывет на - брат(вася, коля).

Фраза «брат (вася, коля)» является фактом, у нее пустое тело, поэтому подцель «брат» сразу же оказывается успешной. Теперь интерпретатор помещает в вершину стека вторую подцель правила дядя - «отец (коля, X).»:

активные запросы фразы программы

?-дядя(вася, X). - указывет на - дядя(вася, X):-

брат(вася, коля),

отец(коля, X).

?- брат(вася, коля). - указывет на - брат(вася, коля).

?- отец (коля, X). - указывет на - отец (коля, миша).

отец (коля, саша).

Интерпретатор пытается согласовать подцель «отец (коля, X).» с фразой «отец (коля, миша)». Эта попытка приводит к успеху, в результате чего конкретизируется переменная X, которая получает значение «миша».

Состояние интерпретатора:

активные запросы фразы программы

?-дядя(вася, миша). - указывет на - дядя(вася, миша):-

брат(вася, коля),

отец(коля, миша).

?- брат(вася, коля). - указывет на - брат(вася, коля).

?- отец(коля, миша). - указывет на - отец(коля, миша).

отец(коля, саша).

Фраза «отец(коля, миша).» является фактом, поэтому запрос «отец» сразу же оказывается успешным. Больше подцелей в теле правила «дядя» нет, следовательно, и исходный запрос «дядя» будет успешным. Интерпретатор выводит значение переменной X=миша. При этом весь стек активных запросов сохраняется.