мы изящно реализовали отношение принадлежности через
конк
. Для проверки на принадлежность можно также использовать и
удалить
. Идея простая: некоторый X принадлежит списку
Список
, если X можно из него удалить:
принадлежит2( X, Список) :-
удалить( X, Список, _ ).
3.2.5. Подсписок
Рассмотрим теперь отношение
подсписок
. Это отношение имеет два
аргумента — список L и список S, такой, что S содержится в L в качестве подсписка. Так отношение
подсписок( [c, d, e], [a, b, c, d, e, f] )
имеет место, а отношение
подсписок( [c, e], [a, b, c, d, e, f] )
нет. Пролог-программа для отношения
подсписок
может основываться на той же идее, что и
принадлежит1
, только на этот раз отношение более общо (см. рис. 3.4).
Рис. 3.4. Отношения
принадлежит
и
подсписок
.
Его можно сформулировать так:
S является подсписком L, если
(1) L можно разбить на два списка L1 и L2 и
(2) L2 можно разбить на два списка S и L3.
Как мы видели раньше, отношение
конк
можно использовать для разбиения списков. Поэтому вышеприведенную формулировку можно выразить на Прологе так:
подсписок( S, L) :-
конк( L1, L2, L),
конк( S, L3, L2).
Ясно, что процедуру
подсписок
можно гибко использовать различными способами. Хотя она предназначалась для проверки, является ли какой-либо список подсписком другого, ее можно использовать, например, для нахождения всех подсписков данного списка:
?- подсписок( S, [а, b, с] ).
S = [];
S = [a];
S = [а, b];
S = [а, b, с];
S = [b];
...
3.2.6. Перестановки
Иногда бывает полезно построить все перестановки некоторого заданного списка. Для этого мы определим отношение
перестановка
с двумя аргументами. Аргументы — это два списка, один из которых является перестановкой другого. Мы намереваемся порождать перестановки списка с помощью механизма автоматического перебора, используя процедуру
перестановка
, подобно тому, как это делается в следующем примере:
?- перестановка( [а, b, с], P).
P = [а, b, с];
P = [а, с, b];
P = [b, а, с];
...
Рис. 3.5. Один из способов построения перестановки списка
[X | L]
.
Программа
для отношения
перестановка
в свою очередь опять может основываться на рассмотрении двух случаев в зависимости от вида первого списка:
(1) Если первый список пуст, то и второй список должен быть пустым.
(2) Если первый список не пуст, тогда он имеет вид
[X | L]
, и перестановку такого списка можно построить так, как это показано на рис. 3.5: вначале получить список L1 — перестановку L, а затем внести X в произвольную позицию L1.
Два прологовских предложения, соответствующих этим двум случаям, таковы:
перестановка( [], []).
перестановка( [X | L ], P) :-
перестановка( L, L1),
внести( X, L1, P).
Другой вариант этой программы мог бы предусматривать удаление элемента X из первого списка, перестановку оставшейся его части — получение списка P, а затем добавление X в начало списка P. Соответствующая программа такова:
перестановка2( [], []).
перестановка2( L, [X | P] ) :-
удалить( X, L, L1),
перестановка2( L1, P).
Поучительно проделать несколько экспериментов с нашей программой перестановки. Ее нормальное использование могло бы быть примерно таким:
?- перестановка( [красный, голубой, зеленый], P).
Как и предполагалось, будут построены все шесть перестановок:
P = [ красный, голубой, зеленый];
P = [ красный, зеленый, голубой];
P = [ голубой, красный, зеленый];
P = [ голубой, зеленый, красный];
P = [ зеленый, красный, голубой];
P = [ зеленый, голубой, красный];
no
(нет)
Приведем другой вариант использования процедуры
перестановка
:
?- перестановка( L, [а, b, с] ).
Наша первая версия,
перестановка
, произведет успешную конкретизацию L всеми шестью перестановками. Если пользователь потребует новых решений, он никогда не получит ответ "нет", поскольку программа войдет в бесконечный цикл, пытаясь отыскать новые несуществующие перестановки. Вторая версия,
перестановка2
, в этой ситуации найдет только первую (идентичную) перестановку, а затем сразу зациклится. Следовательно, при использовании этих отношений требуется соблюдать осторожность.
Упражнения
3.3. Определите два предиката
четнаядлина( Список)
и
нечетнаядлина( Список)
таким образом, чтобы они были истинными, если их аргументом является список четной или нечетной длины соответственно. Например, список