Список – это упорядоченная структура элементов, причем элементами могут быть любые термы, включая другие списки.
Пустой список- [ ]
Непустые списки имеют-голову и хвост. Они являются компонентами функтора, обозначаемого точкой ”.”.Например список из одного элемента а представляется так:
(а,[])
где а-голова и []-хвост. Список элементов a,b, и c имеет вид:
(а,(b,(c,[]))).
То есть, за элементом a следует b, который в свою очередь является головой списка .(b,(c,[])).
Другим видом записи списка будет:
._._._[].
На ТП такой список представляется так: [a,b,c]
где a-голова, b,c-хвост списка, который и сам является списком.
Пример 5 Информация о некоторых семьях может выглядеть как предикат со следующей структурой:
.семья(фамилия, имя_отца, имя_матери, [имена детей] )
.семья(Иванов,Иван,Людмила,[Антон,Наташа,Юрий] ).
В этом случае количество детей не имеет значение, а количество аргументов предиката семья всегда одинаково. Поэтому, если записать целевое утверждение:
семья(X,Y,Z,Дети).
То переменные конкретизируются так:
X=”Иванов” Y=”Иван” Z=”Людмила”
Дети=[“Антон”,”Наташа”,”Юрий”]
На ТП есть специальная форма представления списка [X|Y]. Если такой список сопоставляется с другим списком, то X конкретизируется головой, а Y- хвостом того списка, например:
.семья(X,Y,Z,[Det1|Deti]),
то переменные конкретизируются так:
X=”Иванов” Y=”Иван” Z=”Людмила”
Det1=”Антон” Deti=[”Наташа”,”Юрий”].
Пример 6 Определить семью, где имеется ребенок с именем Алекс.
trace
domains
detlist= person*
person= string
predicates
member(person,detlist)
semja(person,person,person,detli
clauses
member(X,[X|_]).
member(X,[_|Y]):-member(X,Y).
semja("Иванов","Иван","Людмила",["Антон","Наташа","Юрий"]).
semja("Сидоров","Петр","Вера",[]).
semja("Поспелов","Сергей","Ира",["Алексей","Татьяна"]).
goal
makewindow(1,121,0,"",12,40,13,40),
semja(F,I1,I2,Det),member("Алексей",Det),
write("Aleks ",F),nl,
write("ОТЕЦ=",I1," МАТЬ=",I2).
При этом предикат member проверяет принадлежность элемента к списку:
Первый дизъюнкт предиката member означает, что искомый элемент находится в голове списка. Если это не так, то выбирается второй дизъюнкт, который отделяет хвост от головы списка и проверяет, находится ли искомый элемент в хвосту. Это происходит рекурсивно до тех пор, пока либо не найдено, что у остатка списка голова является искомым элементом (удача), либо не окажется, что после отделения хваста от головы остался пустой список([]), который уже не расщепляется на голову и хвост (неудача).
Пример 7. Использование встроенного предиката findall(переменная,предикат(...),список_решений)
В списке решений возвращается все решения для указанной переменной в указанном предикате. Для списка решений должна быть указана подходящая область определения.
Например, из множества адресов выбрать определенные:
domains
familija=string
gorod =string
spisok_rai'nllij-familija* /* области определения для */
spisok_gorodov=gorod* /* ответных списков findall */
predicates
adres(familija,eorod)
clauses
adres("Иванов","Киев").
adres("Гринхофс","Рига").
adres("Шевченко","Киев").
adres("Иванов","Рига").
goal
findall(Gor,adres("Иванов",Gor).Spisok1),
nl,write(Spisokl), /* выводит ["Киев","Рига"] */
findall (Fam, adres( Fam, ) , Spisok2),
nl,wrlte(Splsok2).
/* выводит ["Иванов", "Гринхофс", "Шевченко", "Иванов"] */