Поиск элемента в списке является очень распространенной операцией. Поиск представляет собой просмотр списка на предмет выявления соответствия между объектом поиска и элементом списка. Если такое соответствие найдено, то поиск заканчивается успехом, в противном случае поиск заканчивается неуспехом. Стратегия поиска при этом будет состоять в рекурсивном выделении головы списка и сравнении ее с объектом поиска.
Пример 37: поиск элемента в списке.
domains
list=integer*
predicates
member (integer, list)
clauses
member (Head, [Head |_ ]).
member (Head, [_ | Tail ]):- member (Head, Tail).
goal
member (3, [1, 4, 3, 2]).
Правило поиска может сравнить объект поиска и голову текущего списка, эта операция записана в виде факта предиката member. Этот вариант предполагает наличие соответствия между объектом поиска и головой списка. Отметим, что хвост списка в данном случае не важен, поэтому хвост списка присваивается анонимной переменной. Если объект поиска и голова списка различны, то в результате исполнения первого предложения будет неуспех, происходит возврат и поиск другого правила или факта, с которыми можно попытаться найти соответствие. Для этой цели служит второе предложение, которое выделяет из списка следующий по порядку элемент, то есть выделяет голову текущего хвоста, поэтому текущий хвост представляется как новый список, голову которого можно сравнить с объектом поиска. В случае исполнения второго предложения, голова текущего списка ставится в соответствие анонимной переменной, так как значение головы с писка в данном случае не играет никакой роли.
Процесс повторяется до тех пор, пока первое предложение даст успех, в случае установления соответствия, либо неуспех, в случае исчерпания списка. В представленном примере предикат find находит все совпадения объекта поиска с элементами списка. Для того, чтобы найти только первое совпадение следует модифицировать первое предложение следующим образом:
member (Head, [Head |_ ]):- !.
Отсечение отменяет действие механизма возврата, поэтому поиск альтернативных успешных решений реализован не будет.
Слияние двух списков и получение, таким образом, третьего списка принадлежит к числу наиболее полезных при работе со списками операций. Обозначим первый список L1, а второй список - L2. Пусть L1 = [1, 2, 3], а L2 = [4, 5]. Предикат append присоединяет L2 к L1 и создает выходной список L3, в который он должен переслать все элементы L1 и L2. Весь процесс можно представить следующим образом:
1. Список L3 вначале пуст.
2. Элементы списка L1 пересылаются в L3, теперь значением L3 будет [1, 2, 3].
3. Элементы списка L2 пересылаются в L3, в результате чего тот принимает значение [1, 2, 3, 4, 5].
Тогда программа на языке Турбо-Пролог имеет следующий вид:
Основное использование предиката append состоит в объединении двух списков, что делается при помощи задания цели вида append ([1, 2, 3], [4, 5], L3). Поиск ответа на вопрос типа: append (L1, [3, 4, 5], [1, 2, 3, 4, 5]) – сводится к поиску такого списка L1=[1, 2], который при слиянии со списком L2 = [3, 4, 5] даст список L3 = [1, 2, 3, 4, 5]. При обработки цели append (L1, L2, [1, 2, 3, 4, 5]) ищутся такие списки L1 и L2, что их объединение даст список L3 = [1, 2, 3, 4, 5].