Печать списка в обратном порядке

Процедура "обр_печать" почти идентична процедуре "печатать_элементы". Отличие состоит в том, что "обр_печать" выводит элементы списка на печать в обратном порядке. Это достигается за счет изменения порядка следования подцелей в рекурсивном правиле, так что процедура становится леворекурсивной.

% условие окончания, когда список пуст.

обр_печать ([]). % (1)

% рекурсивное правило.

обр_печать ([Первый; Остаток]): - % (2)

обр_печать (Остаток), % рекурсивный вызов

write (Первый), n1. % вывод первого элемента

|? - обр_печать ([a, b, с]),

с

b

а

да

На рис. 2. 2 изображено дерево доказательства, соответствующее этому запросу.

Форма записи аргументов в заголовке правила

Форма записи аргументов в заголовке правила определяет обстоятельства, при которых оно будет действовать, поскольку заголовок правила должен быть унифицирован с запросом до того, как интерпретатор предпримет попытку обработки тела правила. Например, аргумент в первом правиле процедуры "печатать_элементы" будет унифицироваться только с пустым списком. Аргумент второго правила будет унифицироваться только со списком, содержащим не менее одного элемента (например, элемент « Первый»). Поэтому интерпретатор не будет обрабатывать второе правило, если аргументом служит пустой список.

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

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

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

Процедура "элемент"

% исходный случай: Х является первым элементом списка.

элемент (X, [X | Остаток]). % (1)

% Х не является первым элементом списка, искать Х в

% оставшейся части списка.

элемент (X, [Y | Остаток]): - % (2)

элемент (X, Остаток).

% входит ли элемент b в список [а, b, с]?

|? - элемент (b, [а, b, с]).

да

|? - элемент (b, b).

нет

% выдать элементы списка:

|? -элемент (X, [1, 2, 3]).

Х=1;

Х=2;

Х=З;

нет

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

Процедура "найти_слово''

Процедура "найти_слово" похожа на процедуру "элемент". Различие между ними заключается в том, что процедура "найти_слово" заканчивается либо когда список пуст, либо когда атом обнаружен в списке. Обратите внимание, как форма записи аргументов в заголовке каждой фразы используется для указания обстоятельств применения этой фразы.

% исходный случай № 1: список пуст

найти_слово (Слово, []):— % (1)

write (Слово),

write (' не найдено '), n1.

% исходный случай № 2: переменная Слово унифицируется

% с первым элементом списка

найти_слово (Слово, [Слово | Остаток]). % (2)

% рекурсия, если переменная Слово не унифицируется с

% первым элементом списка

найти_слово (Слово, [Хслово | Остаток]):— % (3)

найти_слово (Слово, Остаток).

Примеры запросов к процедуре "найти_слово":

|? -найти_слово (в, [находится, в, доме]).

да

|? -найти_слово (коровник, [находится, в доме]).

коровник не найдено да

|? -найти_слово (X, [находится, в, доме]),

Х = находится,

Х=в;

Х = доме

Как Вы считаете, какой ответ выдаст интерпретатор, если пользователь еще раз введет символ;?

Процедура "присоединить"'

Все три аргумента процедуры "присоединить" являются списками. Списки, задаваемые в первых двух аргументах, объединяются в один список, возвращаемый через третий аргумент. Процедуру "присоединить" можно также использовать для разбиения списка, представленного третьим аргументом, на два подсписка. Процедура "присоединить" называется обратимой, так как все три ее аргумента - двунаправленные.

% исходный случай: первый аргумент — пустой список

присоединить ([], Список, Список). % (1)

% Взять элемент 1 из начала первого аргумента и поместить

% его в начало третьего аргумента, либо выполнить обрат-

% ное действие:

присоединить ([X | Список1], Список2, [Х | СписокЗ]):— % (2)

присоединить (Список1, Список2, СписокЗ).

|? - присоединить ([a, b, c], [1, 2], Y).

Y= [a, b, c, 1, 2]

|? -присоединить ([а], Х, [a, z, m, n]).

X= [z, m, n]

|? -присоединить (А, В, [1, 2, 3]).

А= []

В = [1, 2, 3];

A=[1]

В= [2, 3];

А= [1, 2]

В= [3];

А = [1, 2, 3]

В= [];

нет

Обратите внимание, что в результате последнего запроса были сгенерированы все возможные способы разбиения списка [1, 2, 3] на два подсписка.

Процедура "длина''

Первым аргументом процедуры "длина" является список, а через второй аргумент данная процедура возвращает длину этого списка.

% исходный случай — в пустом списке нуль элементов.

длина ([ ]. 0). %(1)

длина ([F| R], N): - % (2)

длина (R. N1),

N is Nl + 1.

|?— длина ([альфа, бета, гамма], Дл).

Дл=З

|? -дпина ([[а. Ь]. Х]. Дл).

Х=_1

Дл=2

Заметьте, что в последнем запросе список [а, b] считается одним элементом и неконкретизированная переменная Х также считается одним элементом; _1 — это внутреннее обозначение переменной X. Оно выводится на печать, так как в точке получения позитивного ответа на запрос переменная Х не конкретизирована. Программист не может пользоваться таким внутренним обозначением для обращения к переменной.

Соседние файлы в папке Гл.0,1,2,3,4,5,Предисловие