Списки — это объекты, которые имеют конечное число элементов. Объявляют их добавляя «*» (звездочку) в конце предварительно определяемого типа.
domains
intlist=integer* /*Список целых чисел*/
Список — это рекурсивный комбинированный объект, составленный из головы и хвоста. Голова — это первый элемент списка, а хвост – это все остальное (без первого элемента). Хвост списка — всегда список. Голова списка всегда — элемент. Список может иметь 0 или более элементов; пустой список записывается [].
В Прологе список рассматривается как частный случай бинарного дерева:
Элементы списка могут быть любыми, включая и другие списки. Все элементы списка должны принадлежать одному и тому же типу. В Турбо Прологе нельзя смешивать типы в списке.
Для разделения головы и хвоста в списке используются разделители (запятая, [ и |); В голове списка можно выделить несколько элементов, например, список [a, b, c, d] может быть записан как
[a|[b, c, d]] или
[a, b|[c, d]] или
[a, b, c|[d]] или
[a|[b|[c, d]]] или
[a|[b|[c|[d]]]] или даже
[a|[b|[c|[d|[]]]]]
Пустой список нельзя разделить на голову и хвост.
Порядок элементов в списке существенен. Один и тот же объект может встречаться в списке несколько раз.
Главный способ обработки списка — это просмотр его и обработка каждого элемента, пока не будет достигнут конец. Алгоритму этого типа обычно нужно два предложения. Первое из которых говорит, что делать с обычным списком (списком, который можно разделить на голову и хвост). Второе говорит, что делать с пустым списком. Т.е., работа со списком состоит из рекурсивного выделения головы (и, обычно, его обработки), до тех пор, пока список не станет пустым.
/* Листинг программы Lab4_1.pro*/
domains
intlist=integer*
predicates
cr_list (intlist,intlist) % Создание списка
do % Главная процедура
list (intlist) % Вывод списка — правая рекурсия
list1 (intlist) % Вывод списка — левая рекурсия
member (integer,intlist) % Является ли элемент членом списка
length(intlist,integer) % вычисление длины списка (левая рекурсия)
length_of(intlist,integer,integer) % вычисление длины списка (правая рекурсия)
app_el (integer,intlist,intlist) % Добавить элемент в начало списка
ins (integer,intlist,intlist) % Добавить элемент в произвольную позицию списка
del_el (integer,intlist,intlist) % удаление первого вхождения элемента в список
delete (integer,intlist,intlist) % удаление всех вхождений элементов в список
append(intlist, intlist, intlist) % Добавить второй список в конец первого списка
sublist(intlist,intlist) % подсписок списка
perest(intlist,intlist) % перестановки
clauses
list([]).
list([X|XS]):-write(X,» «),list(Xs).
list1([]).
list1([X|T]):-list1(T),write(X,» «).
member(X,[X|Xs]).
member(X,[Y|Ys]):-member(X,Ys).
app_el(X,L,[X|L]).
cr_list(List,NewList):-readint(X),
X<>999,!,
app_el(X,List,TempList),
cr_list(TempList,Newlist).
cr_list(List,List).
length([],0).
length([_|Xs],N):- length(Xs,N1),N=N1+1.
length_of([], Result, Result).
length_of([_|T], Result, K):-
NewK = K + 1,
length_of(T, Result, NewK).
append([], List, List).
append([X|L1], List2, [X|L3]):- append(L1, List2, L3).
del_el(X,[X|T],T).
del_el(X,[Y|T],[Y|T1]):-
del_el(X,T,T1).
delete(X,[X|Xs],Ys):-delete(X,XS,Ys).
delete(Z,[X|Xs],[X|Ys]):-delete(Z,Xs,Ys).
delete(X,[],[]).
sublist(S,L):- append(L1,L2,L),append(S,L3,L2).
ins(X,List,Biglist):-del_el(X,Biglist,List),list(Biglist),nl,fail.
perest([],[]).
perest(L,[X|P]):- del_el(X,L,L1),perest(L1,P).
do:-
write(«Введите элементы списка. Признак окончания ввода — 999.»),nl,
cr_list([],Nlist),!,nl,
list(NList),nl,
length(NList,N),
write(«Количество элементов списка=»,N),nl.
/*goal
do.
*/
Рассмотрим предикат append, определенный в программе Lab4_1.PRO. Загрузите программу и закомментируйте секцию goal. Запустите следующие целевые утверждения:
append([1, 2, 3], [5, 6], L).
append([1, 2], [3], L).
В Прологе один и тот же предикат может иметь несколько вариантов использования.
Классические предикаты Пролога member (элемент списка) и append (добавить элемент в список) дают возможность проверить, есть ли элемент в списке, и проверить есть, ли один список в другом соответственно.
Рассматривая append с декларативной точки зрения, вы определили отношение между тремя списками. Это отношение все равно останется, если List1 и List3 — известны, а List2 — нет. Оно также справедливо, если известен только List3. Например, чтобы определить, какие из двух списков можно обьединить для того, чтобы получить известный список, надо составить целевое утверждение следующей формы:
append(L1, L2, [1, 2, 4]).
По этому целевому утверждению Турбо Пролог найдет следующие решения:
L1 = [], L2 = [1,2,4]
L1 = [1], L2 = [2,4]
L1 = [1,2], L2 = [4]
L1 = [1,2,4], L2 = []
4 Solutions
Можно также применить append, чтобы определить какой список можно подсоединить к [3, 4], чтобы получить список [1, 2, 3, 4]. Запустите целевое утверждение:
append(L1, [3,4], [1,2,3,4]).
Турбо Пролог найдет решение:
L1 = [1,2].
Предикат append определил отношение между входным набором и выходным набором таким образом, что отношение применимо в обоих направлениях. Задавая такое отношение, получаем ответы на вопросы: Как относится выход с данным входом? Или Как относится вход с данным выходом?
Состояние аргументов при вызове предиката передается как поток параметров. Аргумент, который присваивается или назначается в момент вызова, называется входным аргументом и обозначается буквой (i); а свободный аргумент — это выходной аргумент, обозначается буквой (o).
У предиката append есть возможность манипулировать и переставлять части, как необходимо. Однако, не для всех предикатов имеется возможность быть вызванными с потоком параметров. Когда в предложении Пролога можно работать с потоком параметров, оно называется инверсным предложением. Когда вы записываете собственные предложения в Турбо Прологе, помните, что инверсное предложение имеет дополнительные преимущества, и создание инверсных предложений добавляет мощности предикатам, которые вы пишете.
