Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
nonprocedurala (PNP)
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
Motivatia necesitatii PNP
Programare
Nonprocedur Orientata pe
Procedurala Concurenta ...
ala obiecte
Logica Functionala
Avantajele programelor PNP
Out Directionat
aduna aduna
Nedirectionat
In In In/Out In In
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
aduna aduna
3 4 X= 3 4
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
aduna aduna
3 4 X=7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
aduna(3, 4, X) aduna(3, 4)
X=7 7
Programare LOGICA versus programare
FUNCTIONALA. Schema
Programare logica Programare functionala
• Patratul sumei a doua numere • Patratul sumei a doua numere
Out
patrat patrat
In
In In/Out Out
aduna aduna
In In In/Out In In
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere • Patratul sumei a doua numere
patrat patrat
aduna aduna
3 4 3 4
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere • Patratul sumei a doua numere
patrat patrat
aduna aduna
3 4 X=7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere • Patratul sumei a doua numere
49
patrat patrat
Y = 49 7
aduna aduna
3 4 X=7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Patratul sumei a doua numere • Patratul sumei a doua numere
X=7 Y = 49 49
Programare LOGICA versus programare
FUNCTIONALA. Schema
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
succes/esec
succes/esec =
In Out
aduna aduna
In In In In In
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
aduna aduna
3 4 7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
succes =
7 7
aduna aduna
3 4 7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
succes
succes =
7 7
aduna aduna
3 4 7 3 4
Programare LOGICA versus programare
FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
aduna(3, 4, 7) 7 = aduna(3, 4)
succes 7=7
succes
Scopurile acestui curs
• Bibliografie:
▫ Leon Sterling, Ehud Shapiro, The Art of Prolog, Second Edition:
Advanced Programming Techniques (Logic Programming), MIT
Press, 1994.
▫ Internet.
LISP
• Numele provine de la LISt Processing.
• Bibliografie:
▫ Stuart C.Shapiro, Common Lisp: An Interactive Approach,
Computer Science Press, 1992.
▫ Internet.
I know what you did last summer… term
• A trecut mult de anul trecut…
• Atomii:
▫ Sunt alcatuiti de obicei din litere şi cifre, având
primul caracter o literă mică.
▫ salut, douaCuvinteAlaturate, un_atom, a2 sunt
atomi
▫ nu-este-atom, 5nu, _faraunderline, Literamare nu
sunt atomi
▫ ’acesta-este-atom’, ’inca un atom’, ’Atom’ - atomi
Tipuri de termeni in Prolog
• Variabilele:
▫ Sunt asemănatoare atomilor, cu excepţia că ele
încep cu literă mare sau cu underline (_).
▫ Variabila, _variabila, Alta_vaRiabila2 sunt
variabile.
• Variabila anonima:
▫ Sunt variabilele care incep cu underline (_).
▫ Apare in doua cazuri:
Cand valoarea unei variabile nu este folosita in
cadrul unui clauze.
In lucrul cu predicatul fail.
Variabila anonima - continuare
• Variabila nu este folosita in cadrul unui predicat:
semn(X, 1) :- X >= 0.
semn(_X, -1).
factorial(0,1).
factorial(N,F) :- N>0, N1 is N-1, factorial(N1,F1), F
is N * F1.
?- factorial(3, X).
X=6
Recursivitatea in Prolog
• Implementarea functiilor recursive, de exemplu,
Fibonacci:
fibonacci(1, 1).
fibonacci(2, 1).
fibonacci(N, F):- N1 is N – 1, N2 is N – 2,
fibonacci(N1, F1), fibonacci(N2, F2), F is F1 + F2.
?- fibonacci(3, X).
X=2
Liste in Prolog
• Data viitoare…
Liste in Prolog
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2/56
Liste
• Sunt structuri care se folosesc pentru reprezentarea unei
secvenţe ordonate de termeni Prolog.
▫ [doar, un, exemplu]
▫ []
▫ [a, b, c, d, e]
▫ [1, 21, 4, -17]
▫ [4, [6], c, [-1, 12]]
• Virgula folosită în construcţia listelor este doar un
separator de argumente.
• Listele sunt secvenţe ordonate de termeni Prolog, deci
lista [a,b,c] nu este aceeaşi cu lista [a, c, b].
3/56
X=a
Y = [b, c, d]
4/56
X=a
Y = [b, c, d]
X – lista initiala
A – elementul de adaugat
Y – lista care se va obtine
6/56
• Y = [a, b, c | X]
7/56
• X = [A, B, C | Y]
Unificarea la liste
• [a, b, c] = [c, a, b]
▫ întoarce No pentru că ordinea termenilor
contează
• [X] = [a, b, c]
▫ întoarce No pentru că cele două liste au lungimi
diferite
Unificarea la liste
• [X,Y|Z] = [a, b, c, d]
▫ întoarce Yes şi X = a, Y = b, Z = [c, d]
• [X|Y] = []
▫ întoarce No pentru că lista vidă nu poate fi
descompusă
• [X|Y] = [a]
▫ întoarce Yes şi X = a, Y = []
10/56
Unificarea la liste
• [a, b | X] = [A, B, c]
• [a, b] = [b, a]
• [a, X] = [X, b]
11/56
Unificarea la liste
• [a | []] = [X]
• [a, b, X, c] = [A, B, Y]
• [[X],Y] = [a, b]
12/56
afis([]).
afis([Prim | Rest]) :- write(Prim), tab(3),
afis(Rest).
14/56
apartine(X, [X | _]).
apartine(X, [Y | Rest]) :- apartine(X, Rest).
nr_elem([], 0).
nr_elem([_ | Rest], N) :- nr_elem(Rest, N1), N is
N1 + 1.
X=3
19/56
suma([], 0).
suma([P|Rest], S) :- suma(Rest, S1), S is S1 + P.
X=6
21/56
?- media([1, 2, 3]).
Media este 2.
22/56
X=3
24/56
?- max([4, 2, 5, 1]).
Maximul este 5.
26/56
?- poz_max([4, 2, 5, 1]).
Maximul se gaseste pe pozitia 3
29/56
inv1([], L, L).
inv1([X|Rest], Temp, L) :- inv1(Rest, [X|Temp],
L).
• Ce presupune interclasarea?
R2, R3).
prefix([], _L).
prefix([X|R1], [X|R2]) :- prefix(R1, R2).
sufix(L, L).
sufix(L, [_Y|Rest]) :- sufix(L, Rest).
?- sufix([1,2,3],[1,2]).
No
?- sublista([1,2], [3,1,2,5,6]).
Yes
?- sublista([1,2], [3, 1, 4, 5, 2])
No L2
L1
44/56
9 0 3 2 4 5 6 7
• Enunt problema:
▫ Se dă o listă: să se obţină două liste din aceasta astfel
încât prima din ele să conţină elementele de pe
poziţiile pare iar a doua pe cele de pe poziţiile impare.
9 0 3 2 4 5 6 7
• Interogare:
▫ ? – pare([ion, marius, mananca, invata, mere, prolog], P, I).
P = [marius, invata, prolog]
I = [ion, mananca, mere]
46/56
9 0 3 2 4 5 6 7
1 4 6 7 8 9 0 3 2 4 5 6 7
• Enunt problema:
▫ Având date o listă şi un element care aparţine
acestei liste, să se specifice pe ce poziţie este situat
elementul în lista dată.
• Avem doua argumente de intrare:
▫ Lista in care se gaseste elementul
▫ Elementul pentru care trebuie sa gasim pozitia
• Vom mai construi un predicat care sa contina si
o variabila contor care este initial 1.
50/56
1 4 6 7 8 9 0 3 2 4 5 6 7
1 4 6 7 8 9 0 3 2 4 5 6 7
• Interogarea:
▫ ? – pozx([ion, petre, marin, olivia], marin, P).
P=3
52/56
Eliminarea duplicatelor
• Enunt problema:
▫ Scrieţi un predicat Prolog care să realizeze
eliminarea duplicatelor dintr-o listă dată.
• Argument de intrare:
▫ O lista data
• Argument de iesire:
▫ Lista rezultata prin eliminarea duplicatelor din
lista data.
• Vom face uz de predicatul apartine/2 prezentat
mai devreme.
55/56
Eliminarea duplicatelor
duplicate([], []).
duplicate([X|R1], L) :- apartine(X, R1), duplicate(R1, L).
duplicate([X|R1], [X|R2]) :- duplicate(R1, R2).
• Interogare
▫ ? – duplicate([7, 9, 7, 11, 11], L).
L = [9, 7, 11]
56/56
Pe saptamana viitoare!
Structuri compuse in Prolog
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2/41
Ce sunt structurile?
• Cea mai mare parte din informaţia pe care vrem să o
reprezentăm într-un program este compusă, adică ea
constă din entităţi care au mai multe atribute diferite
▫ De exemplu, entitatea persoană poate avea mai multe
atribute precum vârstă, înăltime, greutate etc.
• În programele realizate până acum, am utilizat numai fapte şi
reguli care foloseau structuri de date simple.
▫ Argumentele predicatelor folosite au fost atomi sau numere.
• Aceste date simple pot însă fi combinate pentru a construi
tipuri de date complexe numite structuri.
3/41
Ce sunt structurile?
• O structură constă dintr-un functor şi un număr fix
de argumente:
structura(arg1, arg2, …, argn)
• Fiind un termen, structura poate să apară în cadrul
unei clauze oriunde poate apărea o variabilă sau o
constantă.
• Precum toţi ceilalţi termeni folosiţi anterior, nici
structurile nu trebuie declarate
▫ Le folosim direct în cadrul programului, acolo unde
avem nevoie de ele.
4/41
Ce sunt structurile?
• Deşi arată precum predicatele, nu funcţionează
ca acestea.
▫ Predicatele sunt relatii, iar structurile sunt
obiecte.
▫ Diferenţa dintre cele două este realizată de către
Prolog după locul în care apar într-o clauză.
• Structurile nu apar niciodată singure, ci doar ca
argumente pentru predicate.
5/41
Arbori binari
• Un arbore binar are proprietatea că pentru un nod
părinte:
▫ fiecare nod aflat în partea stângă a sa are o valoare numerică
mai mică decât a sa şi
▫ fiecare nod aflat în partea dreaptă a nodului părinte are o
valoare mai mare decât a sa.
4 11
3 6 9 16
9/41
Arbori binari
• Pentru reprezentarea în Prolog, presupunem că fiecare nod are
câte două legături către alţi arbori:
▫ una către subarborele stâng
▫ una către subarborele drept
arb(8, arb(4, arb(3, n, n), arb(6, n, n)), arb(11, arb(9, n, n), arb(16, n, n)))
8
Se reprezinta
asadar sub forma
unei structuri
compuse. 4 11
3 6 9 16
10/41
Arbori binari
• Scrieţi un predicat Prolog care să calculeze suma
elementelor arborelui.
suma(n, 0).
suma(arb(R, n, n), R).
suma(arb(Radacina, S, D), Suma) :- suma(S, S1),
suma(D, S2), Suma is Radacina + S1 + S2.
11/41
Arbori binari
• Scrieţi un predicat Prolog care să verifice
existenta unui număr dat într-un arbore binar.
cauta(n, _):- write(‘Nu exista.’).
cauta(arb(X, _, _), X):- write(‘Numarul exista.’).
cauta(arb(Rad, S, _D), X) :- X < Rad, cauta(S, X).
cauta(arb(_Rad, _S, D), X) :- cauta(D, X).
12/41
Arbori binari
• Scrieţi predicate Prolog care să realizeze parcurgerea
unui arbore binar în preordine, în inordine şi în
postordine.
• Preordine:
1. Vizitam radacina.
2. Vizitam subarborele stang in preordine.
3. Vizitam subarborele drept in preordine.
• Parcurgerea:
▫ 8, 4, 3, 6, 11, 9, 16.
13/41
Parcurgerea in
preordine
• preord(n).
• preord(arb(Rad, S, D)) :-writeln(Rad),
preord(S),
preord(D).
14/41
Parcurgerea in inordine
• Inordine:
1. Vizitam subarborele stang in inordine.
2. Vizitam radacina.
3. Vizitam subarborele drept in inordine.
• Parcurgerea:
▫ 3, 4, 6, 8, 9, 11, 16
15/41
Parcurgerea in postordine
• Postordine:
1. Vizitam subarborele stang in postordine.
2. Vizitam subarborele drept in postordine.
3. Vizitam radacina.
• Parcurgerea:
▫ 3, 6, 4, 9, 16, 11, 8
16/41
Inordine si postordine?
4 11
10
3 6 9 16
18/41
4 11
3 6 9 16
10
19/41
Intrari in Prolog
• Pentru a citi dintr-un fişier nu trebuie decât să
facem din fişierul respectiv canalul curent.
Iesiri in Prolog
• Pentru a scrie într-un fişier trebuie să facem din fişierul
respectiv canalul curent.
• Predicatele care fac acest lucru sunt:
▫ tell(F) – deschide fişierul F pentru scriere şi îl face fişier
de ieşire curent.
Dacă fişierul există deja, conţinutul său este şters, altfel, fişierul
este creat.
▫ append(F) – face acelasi luru ca si tell/1, cu deosebirea
ca, daca fisierul exista, continutul sau nu este sters, ci se
scrie in continuare.
▫ told – închide fişierul de ieşire curent stabilind ca stream
de ieşire ecranul.
25/41
Intrari/iesiri in Prolog
• Predicatul read(-Term) citeşte în variabila Term următorul
termen din fişierul de intrare.
▫ Termenul citit trebuie să se termine cu caracterul punct în
cadrul fişierului.
Exemplu
afis([]).
afis([P|R]) :- write(P), nl, afis(R).
29/41
Rularea programului
• Scriem mai intai intr-un fisier text cateva numere urmate
de caracterul punct, fiecare aflate pe cate un rand.
▫ Il salvam la aceeasi locatie unde se afla si programul.
31/41
Rularea programului
32/41
Alt exemplu
• Dacă fisierul in.txt conţine câte un număr urmat de
punct pe fiecare linie, scrieţi un predicat Prolog care să
introducă în fişierul suma.txt mesajul Suma este urmat
de valoarea sumei numerelor din in.txt.
• Cum se rezolva?
▫ Avem acelasi cod de la programul precedent pentru citirea
elementelor intr-o lista.
▫ Se calculeaza apoi suma elementelor din lista si se scrie
aceasta in fisierul suma.txt.
33/41
sortez([], []).
sortez([P|Rest], Lrez):- selectez(P, Rest, Mici, Mari),
sortez(Mici, MiciSort), sortez(Mari, MariSort),
append(MiciSort, [P|MariSort], Lrez).
Pe saptamana viitoare!
Backtracking
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2/32
Backtracking - exemplu
• Sa consideram programul:
natural(0).
natural(N) :- natural(N1), N is N1 + 1.
Backtracking - exemplu
• Se va genera un ciclu infinit:
▫ numerele succesive sunt generate prin
backtracking.
prefixN(N, [N]).
prefixN(N, [N|L]) :- N1 is N + 1, prefixN(N1, L).
Backtracking
Permutari
litera(a).
litera(b).
litera(c).
litera(d).
9/32
Permutari
permutare(X, Y, Z, T) :- litera(X), litera(Y), litera(Z),
litera(T), X \= Y, X \=Z, Y \= Z, X \=T, Y\=T,Z \=T.
? – permutari.
10/32
Permutari
• Iata permutarile rezultate:
11/32
Taietura (Cut)
• Uneori însă, din cauza backtracking-ului, sunt
întoarse rezultate nedorite.
Taietura (Cut)
Exemplu
locul(1, simion).
locul(2, maria).
locul(3, sorin).
locul(3, cristian).
Mai adaugam:
despre(1, ' este castigatorul
concursului.'). ? – spune(3).
despre(1, ' primeste 100$.'). sorin
despre(2, ' a câştigat locul II.'). a castigat locul III
despre(2, ' primeste 50$.'). primeste 25$.
despre(3, ' a castigat locul III'). cristian
despre(3, ' primeste 25$.'). a castigat locul III
spune(Loc) :- locul(Loc, Cine), primeste 25$.
write(Cine), nl, despre(Loc,
Despre), tab(3),
write(Despre), nl, fail.
15/32
Cut
• Dacă vrem însă să ştim care este primul dintre
cei care au luat locul trei şi câteva lucruri despre
el, avem nevoie de tăietură - adăugăm la
predicatul spune/1 semnul exclamării astfel:
Taietura
• Tăietura se foloseşte de obicei în interiorul unui
predicat unde Prolog-ul a găsit primul răspuns
posibil despre care se doresc mai multe detalii.
• Sau pentru a forţa un predicat să întoarcă un
răspuns negativ (adică fail) într-o anumită
situaţie şi nu vrem să caute alte soluţii.
• Tăietura însă, în general, măreşte complexitatea
codului decât să o simplifice, iar utilizarea ei este
bine să fie evitată pe cât posibil:
▫ se spune chiar că ea reprezintă goto-ul
programării logice.
1
2 3
4 5 6 7
Arbori si grafuri
1 5 9
2 4 6 8
3 7
18/32
Arbori 1
2 3
4 5 6 7
Arbori 1
2 3
% tata(X,Y) - X este tatal lui Y
tata(0,1). 4 5 6 7
tata(1,2).
tata(1,3).
tata(2,4). Aceasta confirma faptul ca
1 este radacina arborelui.
tata(2,5).
tata(2,6).
tata(3,7).
20/32
Parcurgere in adancime 1
2 3
4 5 6 7
• 1, 2, 4, 5, 6, 3, 7
21/32
Parcurgere in adancime 1
4 5 6 7
findall(X, relatie(X,Y), L)
p([]).
p([Nod|Rest]) :- write(Nod), tab(2), findall(D,
tata(Nod, D), LC), append(LC, Rest, Stiva),
p(Stiva).
22/32
Parcurgere in adancime 1
2 3
?-parcurgere.
4 5 6 7
23/32
Parcurgere in latime 1
2 3
4 5 6 7
• 1, 2, 3, 4, 5, 6, 7
24/32
Parcurgere in latime 1
2 3
4 5 6 7
c([]).
c([P|Rest]) :- write(P), tab(2), findall(D, tata(P,
D), LC), append(Rest, LC, Coada), c(Coada).
25/32
Parcurgere in latime 1
2 3
?-parcurgere_latime.
4 5 6 7
26/32
Grafuri orientate
1 5 9
2 4 6 8
3 7
Grafuri orientate
1 5 9
marc(1, 2).
marc(1, 4). 2 4 6 8
marc(1, 5).
marc(3, 2). 3 7
marc(3, 7).
marc(4, 3).
marc(5, 6).
marc(6, 8).
marc(7, 6).
marc(9, 8).
28/32
Grafuri orientate
1 5 9
2 4 6 8
3 7
Grafuri orientate
1 5 9
2 4 6 8
3 7
Grafuri orientate
1 5 9
2 4 6 8
3 7
drum(X, X, L, L).
drum(X, Y, L, Lista) :- marc(X, Z),
not(member(Z, L)), append(L, [Z], L1), drum(Z,
Y, L1, Lista).
31/32
Grafuri orientate
1 5 9
?- drum.
2 4 6 8
3 7
32/32
Pe saptamana viitoare!
Caractere şi stringuri
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2/36
Scrierea caracterelor
• Deci, pentru scrierea mesajului merge, ar trebui
să apelăm:
? – write(’merge’).
4/36
Scrierea caracterelor
? – write(”merge”).
[109, 101, 114, 103, 101]
5/36
Scrierea caracterelor
scriestringul([]).
scriestringul([P|R]) :- put(P), tab(1),
scriestringul(R).
6/36
Scrierea caracterelor
? - scriestringul(”merge”).
7/36
Citirea caracterelor
Citirea caracterelor
Citirea caracterelor
Citirea caracterelor
?-citesc.
11/36
? - string_to_list(String, [99,101,118,97]).
13/36
Concatenare stringuri
Concatenare stringuri
? - string_concat(campu, lung, Tot).
? - string_length(altceva, M).
16/36
?- string_to_atom(String, exemplu).
17/36
• Rest este tot un întreg pozitiv care spune câte poziţii mai
sunt până la sfârşitul şirului iniţial.
• convert_time(+Timp, -Valoare)
Palindrom
Palindrom
inv([], L, L).
inv([X|R], Lt, L) :- inv(R, [X|Lt], L).
28/36
Palindrom
29/36
Vocale
• Având un text introdus în fişierul intrare.txt, să
se numere câte vocale se găsesc în acesta.
• Il deschid in citire.
Vocale
vocale :- see('intrare.txt'), numar(0), seen.
verific(Caracter, N, N1) :-
string_to_list(aeiouAEIOU,Lista),
member(Caracter, Lista), N1 is N + 1.
verific(_, N, N).
31/36
Vocale
32/36
Permutari de caractere
Permutari de caractere
permut :- write('Introduceti cuvantul pentru care
generam permutarea:'), read(Cuvant),
string_to_list(Cuvant, CLista), permut(CLista).
scr([]).
scr([P|R]) :- put(P), scr(R).
34/36
Permutari de caractere
permut([], []).
permut(L, P) :- selecteaza(X, L, Rest),
permut(Rest, RestPerm), P = [X|RestPerm].
Permutari de caractere
36/36
Pe saptamana viitoare!
Baze de date dinamice
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2/61
Adaugare clauze
Retragere clauze
Exemplu
• Presupunem că avem următoarele fapte într-un
fişier Prolog:
copil(ionut).
copil(marian).
copil(simona).
Apelare
• Cu un apel de forma:
? - copil(C).
Adaugare clauze
• Dacă se iveşte un nou copil, şi anume, Iulia, trebuie
să avem în vedere faptul că ea este cea mai mică.
Avem nevoie de un apel de forma:
? – asserta(copil(iulia)).
Retragere clauze
• Să luăm în continuare cazul în care Simona a
trecut de vârsta la care mai poate fi numită copil.
Pentru a o elimina din baza de date, apelăm:
? – retract(copil(simona)).
Adaugare clauze
• Să presupunem, în continuare, că toate
personajele prezentate mai sus, cât timp au fost
copii, au fost buni prieteni.
? – assert((prieteni(X,Y):-copil(X), copil(Y))).
10/61
Retragere clauze
? – retractall(copil(_)).
11/61
Exerciţiu
• Presupunem că avem următoarea schemă a unei
case:
12/61
Exerciţiu
• Definiţi:
▫ legăturile dintre camere (eventual printr-un
predicat numit uşă)
Exerciţiu
• La un moment dat, dacă se apeleaza un predicat
numit mergi/1, sistemul să spună:
▫ care este camera în care se află subiectul
Exemplu
?- mergi(bucatarie).
Esti in birou
Ai mers in bucatarie
Poti merge in:
birou
sufragerie
subsol
? – mergi(hol).
Nu poti ajunge direct din bucatarie in hol
15/61
Rezolvare
:-dynamic aici/1.
usa(birou, hol).
usa(bucatarie, birou).
usa(hol, sufragerie).
usa(bucatarie, subsol). Trebuie specificat faptul ca
vom defini un predicat in mod
usa(sufragerie, bucatarie). dinamic.
Se declara numele predicatului
si numarul sau de argumente.
conectat(X,Y) :- usa(X,Y).
conectat(X,Y) :- usa(Y,X).
aici(birou).
16/61
Rezolvare
mergi(Camera) :- aici(Aici), not(conectat(Aici,
Camera)), write('Esti in '), write(Aici), nl, write('Nu
poti ajunge din '), write(Aici), write(' direct in '),
write(Camera).
Rezultate
18/61
Alt exemplu
Rezolvare
:-dynamic par/1.
:-dynamic impar/1.
declar([]).
declar([P|R]) :- P1 is P mod 2, P1 = 0,
assert(par(P)), declar(R).
declar([P|R]) :- assert(impar(P)), declar(R).
20/61
Rezultate
21/61
Functii de memorare
• O functie de memorare salveaza rezultatele unor
subcalcule pentru a putea fi folosite direct, in
apelari viitoare, fara a mai fi recalculate.
Functii de memorare
• Se verifica veridicitatea faptului respectiv si, in caz
afirmativ, se introduce in memoria Prolog-ului.
retin(deductie(arg1, …, argn)):-deductie(arg1, …,
argn), asserta(deductie(arg1, …, argn)).
hanoi1(N,A,B,_C,[(A,B)]):-N = 1.
hanoi1(N,A,B,C,M):-N > 1, N1 is N - 1,
hanoi1(N1,A,C,B,M1),
hanoi1(N1,C,B,A,M2),append(M1, [(A, B)|M2],
M).
afis([]).
afis([X|Rest]):-writeln(X), afis(Rest).
26/61
hanoi(N,A,B,_C,[(A,B)]):-N = 1.
hanoi(N,A,B,C,M):-N > 1, N1 is N - 1,
retin(hanoi(N1,A,C,B,M1)),
hanoi(N1,C,B,A,M2),append(M1, [(A, B)|M2], M).
retin(P):-P, asserta(P).
27/61
Rulare
A C B
Predicatul REPEAT
31/61
Repeat
• Dacă o anumită clauză trebuie satisfăcută de
mai multe ori, facem apel la predicatul fail care
face ca Prologul să încerce să găsească toate
soluţiile (presupunând că nu folosim tăietura).
Repeat
• În general, predicatul repeat este folosit în construcţii de
forma:
Exemplu
• Următorul predicat citesc/0 face citirea de la
tastatură a unor valori pe care le afişează apoi
utilizatorului.
• Procesul se termină atunci când utilizatorul
introduce gata.
Exemplu
35/61
Alt exemplu
Rezolvare
Rezultate
38/61
Alt exemplu
Alt exemplu
• Utilizatorului îi va fi prezentat un meniu care îi
permite să facă următoarele operaţii:
Alt exemplu
• Continuare meniu:
Faptele
persoana(andrei, barbat, [cristi, elena]).
persoana(cristi, barbat, [adriana, marius, ovidiu]).
persoana(elena, femeie, [ana]).
persoana(marius, barbat, []).
persoana(ovidiu, barbat, []).
persoana(george, barbat, []).
persoana(adriana, femeie, []).
persoana(ana, femeie, [george]).
42/61
Adaugarea copilului X la Y
Adaugarea copilului X la Y
48/61
Eliminarea copilului X de la Y
Eliminarea copilului X de la Y
Eliminarea copilului X de la Y
51/61
salvez.
53/61
Meniul
meniu :- nl, nl, tab(15), write('Selectati un numar
din cadrul meniului'), nl, nl, write('1. Listare
baza de cunostinte.'), nl, write('2. Adaugare
persoana.'), nl, write('3. Eliminare persoana.'),
nl, write('4. Adaugarea lui X ca si copil al lui Y.'),
nl, write('5. Stergerea lui X ca si copil al lui Y.'),
nl, write('6. Eliminarea tuturor persoanelor.'), nl,
write('7. Salvarea bazei de cunostinte intr-un
fisier Prolog.'), nl, write('8. Incarcarea bazei de
cunostinte dintr-un fisier Prolog.'), nl, write('9.
Incheiere.'), nl, nl.
56/61
Partea principala
principal :- repeat, meniu, read(Optiune),
proceseaza(Optiune), nl, Optiune == 9, !.
Partea principala
proceseaza(2) :- adaugare, !.
proceseaza(3) :- stergere, !.
proceseaza(4) :- write('Copilul X: '), read(X),
write('Parintele Y: '), read(Y), copil(X, Y), !.
proceseaza(5) :- write('Copilul X: '), read(X),
write('Parintele Y: '), read(Y), elimcopil(X, Y), !.
proceseaza(6) :- elimintot,!.
58/61
Partea principala
proceseaza(7) :- write('Numele fisierului Prolog
(introduceti-l intre apostrofuri si cu extensia pl):
'), read(NumeFis), salvez(NumeFis), !.
proceseaza(8) :- write('Numele fisierului din care
se face incarcarea (intre apostrofuri si cu
extensia pl): '), read(Fis), deschid(Fis),!.
proceseaza(9).
59/61
Partea principala
afiscopii([]).
afiscopii([P|R]) :- write(P), write(', '), afiscopii(R).
60/61
Rulare
61/61
Pe saptamana viitoare!
Programare functionala.
Fundamentele limbajului LISP
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
Bibliografie
• Internet.
Introducere
• Vom opera cu mediul standard al limbajului
LISP.
▫ Va citi S-expresia.
▫ Lisp o evalueaza.
Caracterul “;” se
foloseste pentru a
comenta o anumita
parte . Rezulta ca ce se
afla dupa el este
ignorat.
Liste in Lisp
• LisP = List Processing
• (1 (2 3.3) 4)
• ()
• (())
Liste
• In acest moment, Lisp-ul citeste expresia care
este data de utilizator si incearca sa o evalueze.
• In schimb, 5 × 3 + 4 se scrie:
(+ (× 5 3) 4)
2x2 + 7x + 5 = 0
• Acestea sunt:
7 7 4 25
2
2 2
Exercitiu
• Le vom scrie Lisp-ului sub forma:
▫ 6 × 3.1416
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2
Stringuri si caractere
• Un string este un vector de caractere.
Exemplu
4
Stringuri
• Un string poate fi oricat de lung si poate contine
caractere precum ENTER.
Exemplu
6
Stringuri
Exemple
8
Stringuri
• Pentru a accesa un anumit caracter in string, se
utilizeaza formularea (char string index).
Exemple
10
Caractere
Exemple
12
Caractere
Exemple
14
Stringuri si caractere
Exemple
Exemple
• Pentru testarea egalitatii a doua stringuri, a
doua poate fi si caracter.
• Pentru acelasi lucru in cazul caracterelor,
amandoua trebuie sa fie de acest fel.
17
Simboluri
• Simbolurile sunt un alt tip de data in Lisp.
Simboluri
• Simbolurile sunt de asemenea folosite drept
variabile.
Exemple
Simboluri
• Cele mai importante simboluri in Lisp sunt T si
NIL.
Simboluri
Simboluri
• Putem scrie simbolurile cu litere mici, Lisp le
converteste la litere mari.
24
Simboluri
• Pentru a testa egalitatea dintre doua simboluri,
se foloseste functia eql.
25
Functia eql
Exemple
27
Simboluri
Exemplu
29
Simboluri
Exemplu
Exemplu
Pachete
Pachete
Pachete
• Atunci cand interactionam cu Lisp, ne aflam deja
intr-un pachet.
Functia describe
• Prin apelul acestei functii Lisp putem afla
diverse proprietati despre obiecte.
Exemple
40
Exemple
41
Pachete
Exemplu
43
Pachete
• Pentru a referi un acelasi simbol din alt pachet,
folosim exprimarea:
nume_pachet::nume_simbol
Pachete
• Sa ne intoarcem acum la pachetul common-lisp-
user si sa aflam informatii despre simbolul ‘paul.
45
Pachete
• Cele doua simboluri din pachete diferite nu sunt
identice decat ca nume.
46
Pachete
• Un simbol poate fi exportat din pachetul sau prin
apelarea functiei export.
nume_pachet:nume_simbol
47
Exemplu
48
Pachete
• Pentru a afla daca un simbol a fost exportat sau
este inca intern intr-un anumit pachet, se poate
proceda precum in cele ce urmeaza.
49
Pachete
• Putem de asemenea defini pachete noi.
50
Pachete
• Daca dorim sa importam un simbol extern
dintr-un pachet in altul folosim functia import.
51
Alte observatii
Exemplu
53
Alte observatii
• Simbolurile standard din pachetul lisp sunt
externe si importate automat in alte pachete.
54
Exemplu
58
Procesarea listelor
• Functia equal spune daca elementele a doua
liste sunt egale doua cate doua sau nu.
61
Alte observatii
• Dupa ce am tastat o forma in Lisp, o putem
imediat reapela cu *; cu ** putem reapela
penultima forma.
63
Pe saptamana viitoare…
Programare in Lisp pur
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2
Exemplu
Simbol
Continuare
15
Continuare
16
Alt exemplu
• Sa definim o functie care sa recunoasca semnul
intrebarii, ?.
17
Problema!
Reformulare
• Intentionam de fapt nu sa recunoastem simbolul
?, ci sa recunoastem orice simbol al carui nume
de afisare este ?.
19
Compilarea si incarcarea
definitiilor
• Pentru a vedea eventualele erori/atentionari,
vom compila fisierul rezultat, prin apelarea
functiei (compile-file “nume.lisp”).
Calculul discriminantului
• Presupunem ca avem o ecuatie de gradul 2 fara
radacini complexe.
• Testul complet al tuturor posibilitatilor va
constitui o parte a cursului viitor.
24
Functii predicat
• Acestea sunt functiile care intorc fie True (T), fie
False (NIL).
Exemple
27
Pe saptamana viitoare…
Expresii conditionale
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
2
Conditionalul
• Lisp are doua tipuri de expresii conditionale:
▫ IF
▫ COND
Exemple simple
4
Conditionalul COND
• Expresia IF este potrivita pentru a alege intre
doua calcule pe baza unui singur test.
Conditionalul COND
• Functia COND are sintaxa (cond (p1 e1) … (pn
en)):
▫ Evalueaza pi-urile in ordine pana cand unul dintre
ele, pj, este true.
▫ Atunci intoarce ej.
▫ Daca niciun pi nu este evaluat ca True, atunci
intoarce False.
Recursivitate
12
Observarea recursivitatii
14
Functia ASSERT
• Pentru a evita argumente gresite, atunci cand
definim o functie putem folosi constructia assert.
• Sintaxa acesteia este:
(assert asertie (variabile_de_schimbat) string
variabile_mentionate)
▫ Asertia este evaluata.
▫ Daca este True, functia se executa normal.
16
Functia ASSERT
(assert asertie (variabile_de_schimbat) string
variabile_mentionate)
▫ Daca este False, Lisp printeaza o eroare:
Ii da utilizatorului optiunea de a termina sau de a
schimba valorile acelor variabile_de_schimbat.
Mesajul din string este afisat.
In acest string putem mentiona anumite variabile,
scriind ~S pentru fiecare si trecandu-le in cadrul
campului variabile_mentionate.
17
Recursivitatea la liste
• Ca prim exemplu, sa incercam definirea versiunii
proprii a functiei length, care determina
lungimea unei liste.
(
26
Pe saptamana viitoare…
Recursivitate – continuare
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
Testarea daca e1 se afla inaintea lui e2
in lista l
Numarul aparitiilor unui element intr-o
lista
Testarea egalitatii elementelor a doua
liste
Elementul de pe pozitia n din lista l
Obtinerea listei elementelor de dupa
pozitia n
Construirea copiei unei liste
Concatenarea a doua liste
Inversarea unei liste
Transforma un
element simplu in
lista ce contine
acel element.
Inversa – alta solutie
Substituirea primei aparitii a unui
element dintr-o lista cu un element
nou
Transformarea din lista in multime
Reuniunea a doua multimi
Lista cu primele n elemente din lista
data ca argument
Inserarea unui element intr-o multime
Intersectia a doua multimi
Diferenta a doua multimi
Verificarea daca o multime e
submultime a unei alte multimi
Egalitatea a doua multimi – fara a lua
in considerare ordinea elementelor
Produsul cartezian a doua multimi
Vom defini o functie care
cupleaza un element dat
cu fiecare membru al unei
liste, rezultand o lista a
cuplurilor formate.
Cuplarea unui element cu fiecare
membru al unei liste
Prefixul unei liste
Sufixul unei liste
Schimbul intre 2 elemente dintr-o
lista
Pozitia unui element intr-o lista
La apelare, contorul se
initializeaza cu valoarea 1.
Adunarea succesiva a cate doua
elemente dintr-o lista
n− 1
∑ x [ i] x [i 1]
i= 1
Impartirea unei liste in doua liste: prima cu
elemente pare, cea de-a doua cu impare
Impartirea unei liste in doua liste: prima cu
elementele de pe pozitiile pare, cea de-a
doua cu cele de pe pozitiile impare
Determinarea tuturor numerelor pana
la un numar n dat, care sunt divizibile
cu un numar k
Maximul unei liste – Metoda 1
Maximul unei liste – Metoda 2
Maximul unei liste – Metoda 3
Quicksort – sortarea unei liste
Pe saptamana viitoare…
Prolog vs. Lisp prin Exemple
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
Numarul elementelor dintr-o lista
nr_elem([], 0).
nr_elem([_ | Rest], N) :- nr_elem(Rest, N1), N is N1 + 1.
X=3
LISP
(defun lungime(l)
(if (null l) 0 (+ 1 (lungime (rest l)))
)
)
suma([], 0).
suma([P|Rest], S) :- suma(Rest, S1), S is S1 + P.
X=6
LISP
12:15 PM
8/56
12:15 PM
9/56
12:15 PM
Inversarea unei liste
PROLOG
pozi([X|_], 1, X).
pozi([_A|R], I, X) :- I1 is I - 1, pozi(R, I1, X).
LISP
(defun elemi(i l)
(if (= n 1) (first l) (elemi (- n 1) (rest l))
)
)
1 4 6 7 8 9 0 3 2 4 5 6 7
• Enunt problema:
▫ Având date o listă şi un element care aparţine
acestei liste, să se specifice pe ce poziţie este situat
elementul în lista dată.
• Avem doua argumente de intrare:
▫ Lista in care se gaseste elementul
▫ Elementul pentru care trebuie sa gasim pozitia
• Vom mai construi un predicat care sa contina si
o variabila contor care este initial 1.
14/56
1 4 6 7 8 9 0 3 2 4 5 6 7
LISP
(defun pozitia (l el p)
(if (eql el (first l)) p (pozitia (rest l) el (+ p 1))))
>(poz ‘(a b c d e) ‘d 1)
4
15/56
LISP
(defun sterg (l el)
(cond ((null l) ‘())
((eql (first l) el) (sterg (rest l) el))
(t (cons (first l) (sterg (rest l) el)))
)
>(sterg ‘(1 4 6 8 6 12 6) 6)
(1 4 8 12)
Eliminarea duplicatelor dintr-o
lista
• Enunt problema:
▫ Să se realizeze eliminarea duplicatelor dintr-o listă
dată.
• Argument de intrare:
▫ O lista data
• Argument de iesire:
▫ Lista rezultata prin eliminarea duplicatelor din lista
data.
• Luam fiecare element din prima lista si verificam
daca apartine restului listei (adica daca mai apare in
lista).
▫ Daca nu mai apare, atunci il adaugam in lista rezultat
▫ Altfel, nu il adaugam.
12:15 PM
Eliminarea duplicatelor dintr-o
lista
PROLOG
duplicate([], []).
duplicate([X|R1], L) :- apartine(X, R1),
duplicate(R1, L).
duplicate([X|R1], [X|R2]) :- duplicate(R1, R2).
(defun duplicate(l)
(cond ((null l) '())
((member (first l) (rest l)) (duplicate (rest l)))
(t (cons (first l) (duplicate (rest l))))
)
))
>(duplicate ‘(7 9 7 11 11))
(9 7 11)
19/56
?- max([4, 2, 5, 1]).
Maximul este 5. LISP
(defun maxim2 (l max)
(cond ((null l)
max)
(defun maxim1
(l)
21/56
?- poz_max([4, 2, 5, 1]).
Maximul se gaseste pe pozitia 3
24/56
(defun pozm (l m p c)
(cond ((null l) p)
((> (first l) m) (pozm (rest l) (first l) c (+ c 1)))
(t (pozm (rest l) m p (+ c 1)))
)
)
> (poz_max ‘(4 2 5 1)
3
25/56
• Ce presupune interclasarea?
• Daca una dintre ele este vida, lista rezultat este cealalta.
27/56
interclasez([], L, L).
interclasez(L, [], L).
interclasez([P1|R1], [P2|R2], [P1|R3]) :- P1 < P2,
interclasez(R1, [P2|R2], R3).
interclasez([P1|R1], [P1|R2], [P1|R3]) :- interclasez(R1, R2, R3).
interclasez(R1, [P2|R2], [P2|R3]) :- interclasez(R1, R2, R3).
?- sufix([1,2,3],[1,2]).
No
?- sufix([1, 2, 3], [3]).
Yes LISP
(defun sufix (l1 l2)
(cond ((null l2) nil)
((equal l1 l2) t)
(t (sufix l1 (rest l2)))))
• Enunt problema:
• Enunt problema:
▫ Se dă o listă: să se obţină două liste din aceasta astfel
încât prima din ele să conţină elementele de pe
poziţiile pare iar a doua pe cele de pe poziţiile impare.
PROLOG
sortez([], []).
sortez([P|Rest], Lrez):- selectez(P, Rest, Mici, Mari), sortez(Mici,
MiciSort), sortez(Mari, MariSort), append(MiciSort, [P|MariSort],
Lrez).
Ruxandra Stoean
http://inf.ucv.ro/~rstoean
ruxandra.stoean@inf.ucv.ro
Avantajele programelor PNP
curent = genereaza_nod(stare_initiala[problema])
Cat timp este posibil executa
urmator = un succesor al nodului curent
Daca eval(urmator) < eval(curent) atunci
intoarce curent
curent = urmator
Sfarsit cat timp
6/17
Dezavantaje hill-climbing
• Maxime locale: este vorba de un varf care este
mai mic decat cel mai inalt varf din spatiul
starilor. Cand se ajunge la maxime locale,
algoritmul se opreste pentru ca nu mai poate
cobori dealul.
▫ Solutia gasita poate fi foarte slaba!
7/17
Problema comis-voiajorului
• Problema:
▫ Se dau n oraşe
▫ Să se găsească un tur
complet de lungime
minimală
• Reprezentare:
▫ Etichetăm oraşele 1, 2, … , n
▫ Un tur complet este o
permutare (pt. n =4:
[1,2,3,4], [3,4,2,1])
• Spaţiul de căutare este imens:
pentru 30 de oraşe sunt 30!
1032 tururi posibile!
Implementarea in Prolog
dist(1,2,10). dist(3,4,5).
• Inregistrarea oraselor dist(1,3,25). dist(3,5,20).
si a distantelor dintre dist(1,4,30). dist(3,6,25).
acestea se va realiza dist(1,5,15). dist(3,7,7).
prin adaugarea de dist(1,6,30). dist(4,5,30).
dist(1,7,40). dist(4,6,15).
fapte si formularea dist(2,3,20). dist(4,7,20).
comutativitatii. dist(2,4,10). dist(5,6,17).
dist(2,5,25). dist(5,7,10).
dist(2,6,35). dist(6,7,10).
d(A,B,X):-dist(A,B,X). dist(2,7,45). orase(7).
d(A,B,X):-dist(B,A,X).
Predicatul principal
• Apeleaza algoritmul de hill-climbing si afiseaza drumul
optim si costul sau.
• Se specifica de asemenea configuratia principala si
numarul de iteratii (considerat drept conditie de oprire).
start([1, 2, 3, 4, 5, 6, 7]).
iteratii(200).
Algoritmul de hill-climbing
• Se implementeaza functia definita in algoritm.
• Daca nu s-a ajuns la numarul de iteratii maxim, se
incearca “urcarea” intr-o configuratie succesoare.
• Daca se va reusi, nodul curent devine cel nou gasit si se
reapeleaza predicatul recursiv.
climb(Drum, F, DrumNou):-mutatie(Drum,
Drum1), eval(Drum1, FNou), FNou < F,
DrumNou = Drum1.
climb(Drum, _, Drum).
Evaluarea unei configuratii
• Evaluarea presupune costul drumului asociat
unei configuratii, adica suma distantelor dintre
orasele din circuit.
eval1([_], 0).
eval1([X,Y|Rest], F):-d(X,Y,C), eval1([Y|Rest], F1),
F is F1 + C.
ultim([X], X).
ultim([_|Rest], X):-ultim(Rest, X).
Mutarea intr-un nod succesor
• Presupune, de fapt, aplicarea unui operator de mutatie
asupra configuratiei curente.
• Se genereaza aleator doua pozitii si valorile
corespunzatoare sunt interschimbate.
cauta([X|_], 1, X).
cauta([_|Rest], Poz, El):-Poz1 is Poz - 1, cauta(Rest, Poz1,
El).
schimba([], _, _, []).
schimba([X|Rest], A, B, [B|Rest1]):- X == A, schimba(Rest,
A, B, Rest1).
schimba([X|Rest], A, B, [A|Rest1]):- X == B, schimba(Rest,
A, B, Rest1).
schimba([X|Rest], A, B, [X|Rest1]):- X \= A, X \= B,
schimba(Rest, A, B, Rest1).
Implementarea in Lisp
• Inregistrarea conexiunilor dintre orase si costurilor asociate.
(defun porneste ()
(hill_climber '(n1 n2 n3 n4 n5 n6 n7) 0))
(defun fl (l)
(cons (gaseste (first (last l)) (first l)) '()))
Lista costurilor asociate drumului
• Pentru doua orase, se cauta pozitia celui de-al
doilea in lista de conexiuni a primului.
• Apoi se cauta costul corespunzator acestei pozitii
in lista costurilor asociat primului oras.
(defun transforma (l)
(if (null (rest l)) '() (cons (gaseste (first l) (second l))
(transforma (rest l)))))
(defun gaseste (x y)
(cauta (get x 'costuri) (cauta2 (get x 'conectat) y 1))
)
Doua functii de cautare
; intoarce elementul de pe pozitia poz din lista l
(defun cauta (l poz)
(if (= poz 1) (first l) (cauta (rest l) (- poz 1))
)
)
return evaluare;
}
Mutatia asupra unei solutii
public void mutatie()
{
int p1 = -1, p2 = -1;