Упражнение 3.
Списъци- основни понятия.
 
 

Задачите от миналия път, които останаха за практикума:

1.Напишете предикат, който има два аргумента елемент и списък и е верен, ако елементът е последен елемент на списъка.

last(X,[X]).
last(X,[_|Z]):-last(X,Z).

Особености:
-Предикатът върви и когато първият аргумент е фиксирана променлива, а вторият свободна. Например при цел

?-last(a,X).

предикатът ще връща при преудовлетворяване следните стойности за Х:

[a]
Yes.
[_1|[a]]
Yes.

и т. н. По- същественото е, че работи не само като прост разпознавател, а когато първият аргумент е свободна
променлива, а вторият е фиксиран списък, предикатът ще се удовлетвори и ще върне във втория си аргумент последния му елемент.

2.Напишете предикат, който има два аргумента елемент и списък и е верен, ако елементът принадлежи на списъка, но не само на първо, а на произволно ниво.

member(Y,[Y|_]).
member(Y,[_|Z]):-member(Y,Z).
member(Y,[X|_]):-member(Y,X).

Особености:
При преудовлетворяване нещата стоят по същият начин, както при обикновения предикат member от миналия път.

3.Напишете предикат, който има три аргумента първите два са елементите Ел1 и Ел2,а третият е списък и е верен, ако елементите Ел1 и Ел2 принадлежат на списъка в този ред и са последователни.

sl(X,Y,[X,Y|_]).
sl(X,Y,[_|Z]):-sl(X,Y,Z).

4.Напишете предикат, който има два аргумента- списъци и е верен, ако първият аргумент е подсписък на втория.

match([],_).
match([X|L],[X|M]):-match(L,M).

sub([X|L],[X|M]):-match(L,M).
sub(L,[_|M]):-sub(L,M).
sub([],_).

Особености:
Предикатът match проверява дали един списък е начало на друг.

5.Напишете предикат, който има два аргумента- списъци и е верен, ако първият аргумент е списък, в който елементите на втория са изброени в обратен ред.

rev(L1,L2):-rv(L1,[], L2).

rv([], L,L).
rv([X|L], L1,L2):-rv(L,[X|L1], L2).

Особености
Предикатът използва помощен предикат, при който имаме една променлива в повече, която е работна, и в нея натрупваме текущия резултат.

6.Реализирайте предикатите за принадлежност и последен елемент чрез append.

last1(X,Y):-append(_,[X], Y).
member1(X,Y):-append(_,[X|_], L).

7.Реализирайте предикат, който има два аргумента списъци, като вторият е пермутация на първия. Направете предиката така че при свободен втори аргумент и при всевъзможните преудовлетворявания във втория аргумент да се връщат всевъзможните пермутации на първия.

perm([],[]).
perm(L,[H|T]):-append(V,[H|U], L), append(V,U,W), perm(W,T).

Задачи за практикума

1.Реализирайте тъй нареченото наивно сортиране на списък от естествени числа, което се състои в следното: генерирате всевъзможните пермутации на един списък от числа, докато получите такава, която е сортирана. Използвайте вградения предикат =<, който има инфиксен запис.

sort1(L,S):-perm(L,S), is_sort(S).

is_sort(L):-iss(0,L).
iss(_,[]).
iss(N,[M|L]):-N =< M,iss(M,L).

2.Реализирайте quick sort за списъци. Използвайте вградения предикат =< и > които имат инфиксен запис.

hit(_,[],[],[]).
hit(H,[A|X],[A|Y], Z):-A =< H,hit(H,X,Y,Z).
hit(H,[A|X], Z,[A|Y]):-A > H,hit(H,X,Z,Y).

qs([],[]).
qs([H|T], S):-hit(H,T,A,B), qs(A,A1), qs(B,B1),
append(A1,[H|B1], S).
______

Нека разгледаме следната реализация на множествата като структури на Пролог: това да са списъци без повтарящи се елементи.

8.Да се реализира предикатът за включване на едно множество в друго.

subset([], X).
subset([E|X], Y):-in_set(E,Y), subset(X,Y).

Особености
Тук предикатът in_set е обикновен предикат member.

9.Да се реализират предикати за сечение и обединение на две множества.

sech([], X,[]).
sech([X|R], Y,[X|Z]):-in_set(X,Y), sech(R,Y,Z).
sech([X|R], Y,Z):-sech(R,Y,Z).

ob([], X,X).
ob([X|R], Y,Z):-in_set(X,Y), ob(R,Y,Z).
ob([X|R], Y,[X|Z]):-ob(R,Y,Z).

Особености
  -Тези двата предиката работят правилно, ако първият и вторият аргумент са фиксирани, а третият не е. Ако искаме да ги използваме като разпознаватели, трябва да изредим елементите на сечението или обединението във строго фиксиран ред. За да ги направим разпознаватели, трябва да използваме
perm, което най-добре да се оставят да открият сами.
-Да се обърне внимание на реда на клаузите, който тук е много съществен, и ако не искаме да използваме not, е
единствен май.

Задачи за практикума

Нека разгледаме и вградения предикат not, който има един аргумент- цел за Пролог и успява, ако аргументът му не успява и обратното- не успява, ако аргументът му успява, като при това не прави никакви свързвания на свободните променливи, ако успее.

1.Да се реши 9. задача, така че предикатите да отговарят коректно на въпроси при фиксирани три аргумента и редът на изброяване да не е съществен.

2.Да се напише предикат, който е на два аргумента списъци и е верен, ако аргументите му са равни като множества, т. е. не се отчита редът им.
 
 

3.Да се напише предикат, който проверява дали даден списък е множество.

4.Имаме лабиринт, който е описан чрез факти по следния начин: залите са означени с малки букви, а там където има врата, има 1 факт в базата от знания от вида
door(a,b).
Да се напише предикат, който по зададени зали връща пътя, ако има такъв в третия си аргумент като списък.

path(X,X,T,T).
path(X,Y,T,R):-door(X,Z),
 not(in_set(Z,T)), path(Z,Y,[Z|T],R).
path(X,Y,T,R):-door(Z,X),
 not(in_set(Z,T)), path(Z,Y,[Z|T],R).

Забележка: пуска се path(X,Y,[X],R), във третия аргумент само се натрупва текущият резултат.