Sunteți pe pagina 1din 4

Recursivitate in Prolog

Anumite reguli necesita o definitie care se bazeaza chiar pe ea insasi. Pentru exemplificare sa
consideram tema 1 din laboratorul trecut. Ea cerea ca pe baza relatiilor primitive barbat, femeie si
parinte sa se defineasca relatiile tata, mama, fiu, fiica, bunic, bunica, nepot, nepoata.

Sa presupunem acum ca dorim reprezentarea relatiei strabun. Regula ar putea fi exprimata in cuvinte: X
este strabunul lui Y daca exista un sir A1, A2, ... ... An, astfel incit X este parintele lui A1, A1 este
parintele lui A2, ... ... An-1 este parintele lui An si An este parintele lui Y.

La prima vedere am putea exprima regula prin mai multe variante de forma:

strabun(X,Y) :- parinte(X,Y).
strabun(X,Y) :- parinte(X,A1), parinte(A1,Y).
strabun(X,Y) :- parinte(X,A1), parinte(A1,A2), parinte(A2,Y).

... si asa mai departe. Dar daca dorim o regula generala, care sa functioneze indiferent de "distanta"
intre X si Y pe linie ascendenta, va trebui sa scriem o infinitate de reguli de acest tip, din ce in ce mai
lungi.

Rezolvarea corecta consta in definirea relatie strabun intr-o maniera recursiva, in doua reguli, astfel:

Regula 1. X este strabunul lui Y daca X este parintele direct al lui Y.


Regula 2. X este strabunul lui Y daca X este parintele lui Z si Z este strabunul lui Y.

Cele doua reguli pot fi scrise in Prolog astfel:

strabun(X,Y) :- parinte(X,Y).
strabun(X,Y) :- parinte(X,Z), strabun(Z,Y).

Probleme rezolvate

Ex1. Sa se scrie un program care calculeaza n!, unde n! = 1 * 2 * 3 *...* n.

% fact(+N, - NFact)
fact(0,1). % Factorialul lui 0 este 1, punctul de oprire.
fact(N,NFact) :- % Factorialul lui N este NFact daca:
N1 is N - 1, % calculăm N-1 pentru a-l putea pasa ca argument
fact(N1, Rezult), % fie Rezult factorial de (N - 1)
NFact is N * Rezult. % atunci NFact este N inmultit cu factorial de N-1
Ex2. Sa se scrie un program care calculeaza termenul n din sirul lui Fibonacci:
1, 1, 2, 3, 5, 8, 13, 21, ..., in care f(n) = f(n - 1) + f(n - 2), pentru n  2.

% fib(+N, -F)
fibo(1, 1).
fibo(2, 1).
fibo(N, F) :- N > 2, N1 is N - 1, N2 is N - 2, fibo(N1, F1), fibo(N2, F2), F is F1 + F2.

O implementare mai eficienta, care sa contina un singur apel recursiv este:


fibo(N, F) :- fib(2, N, 1, 1, F).
% predicat auxiliar fib(+M, +N, +F1, +F2, -F)
fib(M, N, _ , F2, F2) :- M >= N.
fib(M, N, F1, F2, F) :-
M < N, M1 is M + 1, F1plusF2 is F1 + F2, fib(M1, N, F2, F1plusF2, F).

Probleme propuse
1. Sa se scrie un predicat care calculeaza cel mai mare divizor comun pentru doua numere (folosind
definitia recursiva a lui Euclid).

2. Sa se scrie un predicat 'divizor' care testeaza daca un numar se imparte la altul. Pe baza acestui
predicat sa se scrie un predicat 'prim' care spune daca un numar este prim.

3. Sa se scrie un predicat rezolva_hanoi(N) care sa rezolve problema turnurilor din Hanoi cu N discuri.
Probleme diverse rezolvate in Prolog
Vom prezenta rezolvările în Prolog ale câtorva probleme clasice. Fiecare problemă este prezentată sub
următoarea formă:
1) Enunţul problemei (ipoteze şi concluzie);
2) Rescrierea enunţului sub formă de clauze Prolog;
3) Demonstraţia concluziei prin formularea unei interogări corecte în Prolog.

Problema trezorierului
Ipoteze:
1) Nici un membru al clubului nu are datorii la trezorierul clubului.
2) Dacă un membru al clubului nu a plătit taxa, atunci el are datorii la trezorierul clubului.
3) Trezorierul clubului este un membru al clubului.
Concluzie:
Trezorierul clubului a plătit taxa.

% Ipoteza 1
fara_datorii(X) :- membru(X).
% Ipoteza 2
platit_taxa(X) :- fara_datorii(X).
% Ipoteza 3
membru(trezorier).
% Concluzia
% ?- platit_taxa(trezorier).

Problema parteneriatului
Ipoteze:
1) Tom este corect.
2) Bill nu este partener cu Tom.
3) Dacă două persoane X şi Y sunt corecte, atunci X este partener cu Y.
4) Dacă Bill nu este corect, atunci John este corect.
5) Dacă o persoană X este partener cu Y, atunci şi Y este partener cu X.
Concluzie:
John este partener cu Tom.

% Ipoteza 1
corect(tom).
% Ipoteza 2
not_partener(bill, tom).
% Ipoteza 3
partener(X, Y) :- corect(X), corect(Y), X \= Y.
% Ipoteza 4, se foloseşte şi ipoteza 3, inversată conform principiului reducerii
% la absurd: formula p  q este echivalentă cu !q  !p.
corect(john) :- not_corect(bill).
not_corect(X) :- not_ambii_corecţi(X, Y), corect(Y). % din ipoteza 3
not_ambii_corecţi(X, Y) :- not_partener(X, Y).
% Ipoteza 5
% Este reprezentată în definiţia lui partener (ipoteza 3), care include simetria.
% Concluzia
% ?- partener(john, tom).

Probleme propuse
Să se rescriere enunţurile următoarelor probleme sub formă de clauze Prolog şi să se demonstreze
concluziile prin formularea unor interogări corecte în Prolog.

1. Problema vecinilor
Ipoteze:
1) Ştefan este vecin cu Petre.
2) Ştefan este căsătorit cu o doctoriţă care lucrează la Spitalul de Urgenţă.
3) Petre este căsătorit cu o actriţă care lucreaza la Teatrul Naţional.
4) Ştefan este meloman şi Petre este vânător.
5) Toţi melomanii sunt sentimentali.
6) Toţi vânătorii sunt mincinoşi.
7) Actriţele iubesc bărbaţii sentimentali.
8) Soţii au aceiaşi vecini.
9) Căsătoria şi vecinătatea sunt relaţii simetrice.
Concluzie:
Îl iubeşte soţia lui Petre pe Ştefan?

2. Problema unicornului este o problemă celebră formulată de Lewis Carroll în cartea sa "Alice în
ţara minunilor".

Ipoteze:
1) Leul minte luni, marţi şi miercuri şi spune adevărul în toate celelalte zile.
2) Unicornul minte joi, vineri şi sâmbătă şi spune adevărul în toate celelalte zile.
3) Astăzi Leul spune: "Ieri a fost una din zilele în care eu mint."
4) Tot astăzi Unicornul spune: "Ieri a fost una din zilele în care eu mint."
Concluzie:
Ce zi este astăzi?

S-ar putea să vă placă și