Sunteți pe pagina 1din 31

Capitolul 4

Mecanisme specifice
4.1 Controlul procesului de backtracking: cut i fail
4.1.1

Predicatul cut

Sistemul Prolog intr automat ntr-un proces de backtracking, dac acest lucru este
necesar pentru satisfacerea unui scop. Acest comportament poate fi n unele
situaii deosebit de util, dar poate deveni foarte ineficient n alte situaii. Se
consider urmtorul exemplu de program, n care se definesc valorile unei funcii:
f(X, 0) :- X < 3.
f(X, 2) :- 3 =< X, X < 6.
f(X, 4) :- 6 =< X.

%1
%2
%3

La ntrebarea:
?- f(1, Y).
Y=0
sistemul rspunde indicnd c valoarea funciei pentru X=1 este Y=0. Dac se
pune ntrebarea format din conjuncia de scopuri:
?- f(1, Y), 2 < Y.
No
sistemul semnaleaz eec. Arborii de deducie corespunztori acestor rspunsuri
sunt prezentai n figura 4.1.
Se observ c se ncearc resatisfacerea primului scop cu regulile 2 i 3, dei
acest lucru este evident inutil, datorit semanticii acestor reguli. Cel care a scris
aceste reguli poate cu uurin constata c, dac o valoare mai mic dect 3 pentru
X duce la eecul scopului S din conjuncia de scopuri f(X, Y), S, este inutil s se
ncerce resatisfacerea scopului f, deoarece aceasta nu este posibil. Se poate
mpiedica ncercarea de resatisfacere a scopului f(X, Y) prin introducerea
predicatului cut.

54

CAPITOLUL 4

f(1,Y)
X=1
Y=0
f(1,0)
1<3
SUCCES

f(1,Y), 2<Y
X=1
Y=0
f(1,0)

X=1
Y=2
f(1,2)

X=1
Y=4
f(1,4)

2<0

3=<1

6=<1

INSUCCES

INSUCCES

1=<3

INSUCCES

Figura 4.1. Arborii de deducie a scopurilor f(1,Y) i f(1,Y),2 < Y


Predicatul cut, notat cu atomul special !, este un predicat standard, fr
argumente, care se ndeplinete (este adevrat) ntotdeauna i nu poate fi
resatisfcut.
Predicatul cut are urmtoarele efecte laterale:

La ntlnirea predicatului cut, toate seleciile fcute ntre scopul antet de


regul i cut sunt "ngheate", deci marcajele de satisfacere a scopurilor
sunt eliminate, ceea ce duce la eliminarea oricror altor soluii alternative
pe aceasta poriune. O ncercare de resatisfacere a unui scop, ntre scopul
antet de regul i scopul curent va eua.

Dac clauza n care s-a introdus predicatul cut reuete, toate clauzele cu
acelai antet cu aceasta, care urmeaz clauzei n care a aprut cut, vor fi
ignorate. Ele nu se mai folosesc n ncercarea de resatisfacere a scopului
din antetul clauzei care conine cut.

Pe scurt, comportarea predicatului cut este urmtoarea:


(C1) H :- D1, D2, , Dm, !, Dm+1, , Dn.
(C2) H :- A1, , Ap.
(C3) H.
Dac D1, D2, , Dm sunt satisfcute, ele nu mai pot fi resatisfcute
datorit lui cut. Dac D1, , Dm sunt satisfcute, C2 i C3 nu vor mai fi
utilizate pentru resatisfacerea lui H. Resatisfacerea lui H se poate face
numai prin resatisfacerea unuia din scopurile Dm+1, , Dn, dac acestea
au mai multe soluii.
Utiliznd predicatul cut, definiia funciei f(X, Y) poate fi rescris mult mai
eficient astfel:
f(X, 0) :- X < 3, !.
f(X, 2) :- 3 =< X, X < 6, !.
f(X, 4) :- 6 =< X.

MECANISME SPECIFICE

55

Predicatul cut poate fi util n cazul n care se dorete eliminarea unor pai
din deducie, care nu conin soluii sau eliminarea unor ci de cutare care nu
conin soluii. El permite exprimarea n Prolog a unor structuri de control de tipul:
dac condiie atunci aciune1
altfel aciune2
astfel:
daca_atunci_altfel(Cond, Act1, Act2) :- Cond, !, Act1.
daca_atunci_altfel(Cond, Act1, Act2) :- Act2.
Se observ ns c exist dou contexte diferite n care se poate utiliza
predicatul cut: ntr-un context predicatul cut se introduce numai pentru creterea
eficienei programului, caz n care el se numete cut verde; n alt context utilizarea
lui cut modific semnificaia procedural a programului, caz n care el se numete
cut rou.
Exemplul de definire a funciei f(X, Y) cu ajutorul lui cut este un exemplu
de cut verde. Adugarea lui cut nu face dect s creasc eficiena programului, dar
semnificaia procedural este aceeai, indiferent de ordinea n care se scriu cele
trei clauze.
Utilizarea predicatului cut n definirea predicatului asociat structurii de
control daca_atunci_altfel introduce un cut rou, deoarece efectul programului
este total diferit dac se schimb ordinea clauzelor. Introducerea unui cut rou
modific corespondena dintre semnificaia declarativ i semnificaia procedural
a programelor Prolog.
Se consider exemplul de definire a predicatului de aflare a minimului
dintre dou numere, n urmtoarele dou variante:
min1(X, Y, X) :- X =< Y, !.
min1(X, Y, Y) :- X > Y.
min2(X, Y, X) :- X =< Y, !.
min2(X, Y, Y).

% cut verde
% cut rou

n definiia predicatului min1 se utilizeaz un cut verde; el este pus pentru


creterea eficienei programului, dar ordinea clauzelor de definire a lui min1 poate
fi schimbat fr nici un efect asupra rezultatului programului. n cazul
predicatului min2 se utilizeaz un cut rou, asemntor structurii
daca_atunci_altfel. Dac se schimb ordinea clauzelor de definire a predicatului
min2:

56

CAPITOLUL 4

min2(X, Y, Y).
min2(X, Y, X) :- X =< Y, !.
rezultatul programului va fi evident incorect pentru valori X < Y.
n anumite cazuri, efectul introducerii predicatului cut poate fi mai subtil.
Se consider din nou definiia predicatului membru:
membru(X, [X | _]).
membru(X, [ _ |Y]) :- membru(X, Y).
i o definiie alternativ:
membru1(X, [X| _]) :- !.
membru1(X, [ _ |Y]) :- membru1(X, Y).
Introducerea predicatului cut n definiia primei clauze a predicatului
membru1 este justificat datorit creterii eficienei programului. Odat ce s-a
descoperit c un element este membru al unei liste, este inutil ncercarea de
resatisfacere a scopului. Cu toate acestea, predicatul cut de mai sus nu este un cut
verde, deoarece el schimb comportarea programului n cazul n care se pun
ntrebri n care X este variabila neinstaniat n predicatele membru i
membru1.
?- membru(X, [a, b, c]).
X = a;
X = b;
X = c;
No
trei soluii pentru membru
?- membru1(X, [a, b, c]).
X = a;
No
o soluie pentru membru1.
Efectul introducerii predicatului cut asupra semnificaiei declarative a
programelor Prolog poate fi rezumat astfel:
p :- a, b.
p :- c.

% Semnificaia declarativ este:


% (a b) c
% indiferent de ordinea clauzelor (n general).

MECANISME SPECIFICE

57

p :- a, !, b.
p :- c.

% Semnificaia declarativ este:


% (a b) (~ a c).

p :- c.
p :- a, !, b.

% Semnificaia declarativ este:


% c (a b).

Oportunitatea utilizrii unui cut rou sau a unui cut verde este, dintr-un
anumit punct de vedere, similar cu cea a utilizrii sau nu a salturilor n limbajele
de programare clasic. Dac s-ar rescrie predicatul daca_atunci_altfel folosind
un cut verde, definiia lui ar fi:
daca_atunci_altfel(Cond, Act1, Act2) :- Cond, !, Act1.
daca_atunci_altfel(Cond, Act1, Act2) :- not(Cond), !, Act2.
unde predicatul not(Cond) este satisfcut, dac scopul Cond nu este satisfcut. O
astfel de definiie implic evaluarea lui Cond de dou ori i, dac Cond se
definete ca o conjuncie de scopuri, posibil sofisticate, atunci ineficiena utilizrii
unui cut verde n acest caz este evident. De la caz la caz, programatorul n Prolog
trebuie s aleag ntre claritate, deci pstrarea corespondenei semnificaiei
declarative cu cea procedural, i eficien.
Considerm urmtorul exemplu:
C :- P, Q, R, !, S, T, U.
C :- V.
A :- B, C, D.
?- A.
Execuia scopului C va fi afectat de cut astfel: procesul de backtracking va
fi posibil pe lista de scopuri P, Q, R; totui, ndat ce cut-ul este atins, toate
soluiile alternative ale listei de scopuri P, Q, R sunt eliminate. Clauza alternativ
despre C:
C :- V.
va fi i ea ignorat. Procesul de acktracking va fi totui nc posibil pe lista de
scopuri S, T, U. Scopul printe al clauzei care conine cut-ul este scopul C din
clauza:
A :- B, C, D.
Prin urmare cut-ul va afecta doar execuia scopului C. Pe de alt parte, el nu va fi
vizibil n scopul A. Astfel, procesul de backtracking n cadrul listei de scopuri

58

CAPITOLUL 4

B, C, D va rmne activ, indiferent de cut-ul din clauza folosit pentru a satisface


scopul C.

4.1.2

Predicatul fail

n multe situaii intereseaz att condiiile de satisfacere a scopurilor, ct i


condiiile de nesatisfacere a acestora, deci de eec. Fie urmtoarele fapte Prolog:
bun(gelu).
bun(vlad).
bun(mihai).
Pe baza acestor fapte se poate obine un rspuns afirmativ despre buntatea
lui Gelu, Vlad i Mihai i un rspuns negativ dac se ntreab despre buntatea
oricrei alte persoane. Din acest exemplu se poate vedea c limbajul Prolog
folosete un model de raionament minimal numit ipoteza lumii nchise. Conform
acestui model, tot ceea ce nu este tiut de program, deci afirmat explicit ca
adevrat n program, este considerat fals.
Limbajul Prolog permite exprimarea direct a eecului unui scop cu ajutorul
predicatului fail. Predicatul fail este un predicat standard, fr argumente, care
eueaz ntotdeauna. Datorit acestui lucru, introducerea unui predicat fail ntr-o
conjuncie de scopuri, de obicei la sfrit, cci dup fail tot nu se mai poate
satisface nici un scop, determin intrarea n procesul de backtracking.
Dac fail se ntlneste dup predicatul cut, nu se mai face backtracking.
Enunul "Un individ este ru dac nu este bun." se poate exprima astfel:
bun(gelu).
bun(vlad).
bun(mihai).
rau(X) :- bun(X), !, fail.
rau(X).
?- rau(gelu).
No
?- rau(mihai).
No
?- rau(petru).
Yes
Dac predicatul fail este folosit pentru a determina eecul, cum este cazul
exemplului de mai sus, este de obicei precedat de predicatul cut, deoarece procesul

MECANISME SPECIFICE

59

de backtracking pe scopurile care l preced este inutil, scopul eund oricum


datorit lui fail.
Exist cazuri n care predicatul fail este introdus intenionat pentru a genera
procesul de backtracking pe scopurile care l preced, proces interesant nu din
punctul de vedere al posibilitii de resatisfacere a scopului ce conine fail, ci din
punctul de vedere al efectului lateral al acestuia.
rosu(mar).
rosu(cub).
rosu(soare).
afisare(X) :- rosu(X), write(X), nl, fail.
afisare( _ ).
Scopul afisare(X) va afia toate obiectele roii cunoscute de programul
Prolog datorit procesului de backtracking generat de fail; n acest fel s-a relizat
prin fail o iteraie peste faptele rosu( ). Clauza afisare( _ ) este adugat pentru ca
rspunsul final la satisfacerea scopului s fie afirmativ. n acest caz, introducerea
unui cut nainte de fail ar fi determinat numai afiarea primului obiect rou din
program.
Revenind la combinaia !,fail, se consider n continuare implementarea n
Prolog a afirmaiei: "Mihai iubete toate sporturile cu excepia boxului". Aceast
afirmaie poate fi exprimat n pseudocod sub forma:
dac X este sport i X este box
atunci Mihai iubete X este fals
altfel dac X este sport
atunci Mihai iubete X este adevrat
i tradus n Prolog astfel:
iubeste(mihai, X) :- sport(X), box(X), !, fail.
iubeste(mihai, X) :- sport(X).
Cele dou clauze, de mai sus, pot fi compactate ntr-una singur astfel:
iubeste(mihai, X) :- sport(X), box(X), !, fail ; sport(X).
Predicatul cut utilizat aici este un cut rou. Combinaia !, fail este deseori
utilizat n Prolog i are rolul de negaie. Se mai spune c limbajul Prolog
modeleaz negaia ca eec al satisfacerii unui scop (negaia ca insucces), aceasta
fiind de fapt o particularizare a ipotezei lumii nchise. Combinaia !, fail este
echivalent cu un predicat standard existent n Prolog, predicatul not. Predicatul
not admite ca argument un predicat Prolog i reuete dac predicatul argument

60

CAPITOLUL 4

eueaz. Utiliznd acest predicat, ultimul exemplu dat se poate exprima n Prolog
astfel:
iubeste(mihai, X) :- sport(X), not(box(X)).
Un alt predicat standard este predicatul call, care admite ca argument un
predicat Prolog i are ca efect ncercarea de satisfacere a predicatului argument.
Predicatul call reuete dac predicatul argument reuete i eueaz n caz
contrar. Utiliznd acest predicat, se poate explicita efectul general al predicatului
standard not n urmtorul mod:
not(P) :- call(P), !, fail.
not(P).
Att predicatul not, ct i predicatul call sunt predicate de ordinul II n
Prolog, deoarece admit ca argumente alte predicate.
Ca o aplicaie la cele discutate pn acum, iat cteva exemple:
Ex1. Am definit predicatul care calculeaz maximul dintre dou numere (n prima
parte) astfel:
% max(+X, +Y, -Max).
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.
Cele dou reguli sunt mutual exclusive. Dac prima reuete atunci a doua va eua.
Dac prima eueaz, atunci a doua trebuie s reueasc. Prin urmare, o reformulare
mai eficient este posibil:
dac X Y

atunci Max = X
altfel Max = Y.

Aceasta se scrie n Prolog utiliznd cut astfel:


max(X, Y, X) :- X >= Y, !.
max( _ , Y, Y).
S vedem ce se ntmpl ns atunci cnd dorim s folosim puterea
generativ a limbajului Prolog:

?- max(X, 3, 4).
?- max(3, X, 4).
?- max(X, X, 3).

% max(?X, ?Y, ?Max)


max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.

% max(?X, ?Y, ?Max)


max(X, Y, X) :- X >= Y, !.
max( _ , Y, Y).

X=4
X=4
X=3

X=4
X=4
X=3

MECANISME SPECIFICE

61

Cazuri n care predicatul max trebuie s eueze:


?- max(X, 3, 2).
?- max(3, X, 2).

No
No

No
X=2

Din exemplele prezentate se observ c varianta mai explicit se comport


corect n toate cazurile, n timp ce varianta eficient genereaz rezultate eronate.
De aceea, nainte de a utiliza cut, trebuie s ne gndim n ce context i cum vor fi
apelate predicatele n care el apare, deoarece adesea folosirea lui cut crete
posibilitatea apariiei erorilor de programare.

Ex2. Plasarea a opt regine pe o tabl de ah astfel nct ele s nu se atace ntre ele:
% solutie(?Solutie)
solutie([]).
solutie([X/Y | CelelalteRegine]) :solutie(CelelalteRegine),
membru(Y, [1, 2, 3, 4, 5, 6, 7, 8]),
not(ataca(X/Y, CelelalteRegine)).
% ataca(+Regina, +CelelalteRegine) - verifica daca Regina ataca
CelelalteRegine
ataca(X/Y, CelelalteRegine) :membru(X1/Y1, CelelalteRegine),
(Y1 = Y; Y1 is Y + X1 - X; Y1 is Y - X1 + X).
% membru(?X, ?Lista) - membru generativ
membru(X, [X| _ ]).
membru(X, [ _ |L]) :- membru(X, L).
% model de solutie
model([1/Y1, 2/Y2, 3/Y3, 4/Y4, 5/Y5, 6/Y6, 7/Y7, 8/Y8]).
% toate solutiile
toate :- model(L), assert(count(1)), !,
( solutie(L), retract(count(N)), N1 is N + 1, assert(count(N1)),
write(N), write('.'),write(L), nl, fail ; retract(count( _ )), true).
Cut-ul a fost introdus doar pentru eficien (cut verde), iar parantezele care nchid
disjuncia de conjuncii de scopuri au fost puse din cauza lui.

62

CAPITOLUL 4

Ex3. S scriem predicatul unific(X, Y) care reuete dac X i Y unific, fr


ns a modifica pe X sau pe Y. Folosind predicatul not, putem scrie:
unifica(X, Y) :- not(not(X = Y)).
Dac X i Y unific, adic X = Y reuete, atunci not(X = Y) eueaz, unificarea
fiind desfcut, i not(not(X = Y)) reuete (deci unific(X, Y) reuete), X i Y
rmnnd neunificate.

4.2

Predicate predefinite

Predicatele prezentate pn acum, cu excepia predicatului call, sunt predicate


bazate pe logica cu predicate de ordinul I, modelul Prolog cu semnificaia
declarativ a programelor urmrind ndeaproape modelul logic. n continuare se
prezint o serie de predicate Prolog care nu mai pot fi asimilate cu logica cu
predicate de ordinul I, respectiv: predicate ce decid asupra caracterului unor
argumente, predicate de control a fluxului de execuie a programului i predicate
de ordinul II, numite uneori i metapredicate. Metapredicatele accept ca
argumente alte predicate Prolog, fapte sau reguli, i sunt interesante n special prin
efectul lateral pe care l produc. Toate tipurile de predicate menionate reprezint
extinderea modelului programrii logice cu tehnici de programare care cresc
puterea de calcul a limbajului. Majoritatea predicatelor prezentate n continuare
sunt standard i se gsesc predefinite n orice implementare, o parte sunt specifice
mediului SWI-Prolog, acestea fiind indicate ca atare. O implementare particular
poate conine i alte predicate predefinite suplimentare celor prezentate aici.

4.2.1

Predicate de clasificare a termenilor


var(X)

Predicatul var(X) reuete dac X este o variabil neinstaniat i eueaz n


cazul n care X este o variabil instaniat sau o constant.
Exemple:
?- var(5).
No
?- var(mihai).
No
?- var(X).
Yes

nonvar(X)

MECANISME SPECIFICE

63

Predicatul nonvar(X) este adevrat dac X nu este o variabil neinstaniat.


Acest predicat este opusul prdicatului var(X) i s-ar putea defini astfel:
nonvar(X) :- var(X), !, fail.
nonvar( _ ).

atom(X)
Predicatul atom(X) reuete dac X este un atom Prolog i eueaz n caz
contrar.
Exemple:
?- atom(coco).
Yes
?- atom(100).
No
?- atom(carte(prolog, clocksin)).
No

integer(X)
Predicatul integer(X) reuete dac X este un numr ntreg.
Se consider urmtorul exemplu de program Prolog, care transform o
expresie reprezentat printr-o sum de variabile i constante ntr-o expresie care
conine suma variabilelor plus o constant, care reprezint suma tuturor
constantelor din expresie. Predicatul simplif are dou argumente: primul argument
este forma iniial a expresiei, argument instaniat, iar cel de al doilea reprezint
expresia simplificat, sintetizat de program.
% simplif(Expresie_initiala, Expresie_simplificata)
% Predicat ajutator simpl
% simpl(Ex_initiala, Suma_acumulata, Ex_simplificata).
simplif(Expr, Expr1) :- simpl(Expr, 0, Expr1).
simpl(Expr + A, N, Expr1) :integer(A), !,
N1 is N + A,
simpl(Expr, N1, Expr1).
simpl(Expr + A, N, Expr1 + A) :atom(A), !,
simpl(Expr, N, Expr1).
simpl(Rest, N, N1) :integer(Rest), !,
N1 is Rest + N.

64

CAPITOLUL 4

simpl(Rest, 0, Rest) :- !.
simpl(Rest, N, N + Rest).
La ntrebarea
?- simplif(x + 40 + y + 1 + 55 + x + 2, E).
programul rspunde
E = 98 + x + y + x
n programul de mai sus, definirea predicatului simplif s-a fcut pe baza
unui predicat ajuttor simpl, care conine un argument suplimentar. Acest
argument, instaniat la 0 n cazul primului apel, este folosit ca o variabil de
acumulare pentru calculul sumei constantelor ntregi din expresie.

atomic(X)
Pe baza predicatelor atom(X) i integer(X) se poate defini predicatul
atomic(X), care este adevrat dac X este fie ntreg, fie atom Prolog:
atomic(X) :- atom(X).
atomic(X) :- integer(X).
De multe ori predicatul atomic(X) este predefinit n sistem.

4.2.2

Predicate de control

Predicatul true reuete ntotdeauna, iar fail eueaz ntotdeauna.


Predicatul repeat simuleaz structurile de control repetitive din limbajele
clasice de programare. El are o infinitate de soluii, putndu-se resatisface de
oricte ori este nevoie, fr a umple stiva. Definiia lui ar putea fi:
repeat.
repeat :- repeat.
Acest predicat este predefinit n mediul SWI-Prolog.
Un predicat echivalent ciclului for, care nu este predefinit n SWI-Prolog, se
poate implementa astfel:
% for(Variabla, ValoareInitiala, ValoareFinala, Pas)
for(I, I, I, 0).
for( _, _ , _, 0) :- !, fail.
for(I, I, F, S) :S > 0, (I > F, !, fail ; true)
; S < 0, (I < F, !, fail ; true).
for(V, I, F, S) :- I1 is I + S, for(V, I1, F, S).

MECANISME SPECIFICE

65

Exemple de apeluri:
a :- for(X, 10, -10, -3.5), write(X), tab(2), fail ; true.
b :- for(X, -10, 10, 3.5), write(X), tab(2), fail ; true.
c :- for(X, 10, 10, 0), write(X), tab(2), fail ; true.
?- a.
10 6.5 3.0 -0.5 -4.0 -7.5
Yes
?- b.
-10 -6.5 -3.0 0.5 4.0 7.5
Yes
?- c.
10
Yes
Predicatul for eueaz pentru apeluri incorecte (cicluri infinite) de genul:
for(X, -10, 10, 0).
for(X, 10, -10, 2).
for(X, -10, 10, -2).

4.2.3

Predicate de tratare a clauzelor drept termeni

Predicatele din aceast categorie permit: construirea unei structuri care reprezint
o clauz n baza de cunotinte, identificarea clauzelor din program, adugarea sau
eliminarea unor clauze, reprezentate printr-o structur, n baza de cunotine a
sistemului.

clause(Antet, Corp)
Satisfacerea scopului clause(Antet, Corp) necesit unificarea argumentelor
Antet i Corp cu antetul i corpul unei clauze existente n baza de cunotine
Prolog. La apelul acestui predicat, Antet trebuie s fie instaniat astfel nct
predicatul principal al clauzei s fie cunoscut. Dac nu exist clauze pentru acest
predicat, scopul eueaz. Dac exist mai multe clauze care definesc predicatul
Antet, scopul clause(Antet, Corp) va avea mai multe soluii, fiecare soluie
corespunznd unei clauze de definire a predicatului Antet. Dac o clauz este fapt,
Corp se instaniaz la constanta true.
Exemplu. Considernd definiia predicatului de concatenare a dou liste ca fiind
deja introdus n baza de cunotine Prolog:
% conc(Lista1, Lista2, ListaRez)
conc([], L, L).
conc([Prim|Rest1], L2, [Prim|Rest3]) :- conc(Rest1, L2, Rest3).

66

CAPITOLUL 4

se obin urmtoarele rezultate:


?- clause(conc(A, B, C), Corp).
A = [ ],
B = C,
Corp = true;
A = [_G463|_G464],
C = [_G463|_G467],
Corp = conc (_G464, B, _G467);
No
Utiliznd predicatul clause se poate defini un predicat listc de afiare a
clauzelor care definesc un predicat:
% listc(Antet) - afieaz toat clauzele din baza de cunotine
%
care definesc scopul Antet
listc(Antet) :clause(Antet, Corp),
afis(Antet, Corp),
write('.'), nl, fail.
listc( _ ).
afis(Antet, true) :- !, write(Antet). %1
afis(Antet, Corp) :- write(Antet), write(':'), write('-'), write(Corp).
Efectul acestui program, considernd definiia anterioar a scopului conc, este
urmtorul:
?- listc(conc(_, _, _)).
conc([ ], _G304, _G304).
conc([_G375|_G376],_G304,[_G375|_G379]:conc(_G376,_G304,_G379).
Yes
n definirea primei clauze a predicatului afis utilizarea predicatului cut este
esenial deoarece afiarea clauzelor este bazat pe procesul de backtracking
generat intenionat de introducerea predicatului fail n prima clauz a predicatului
listc. Regula %1 din predicatul afis este necesar, deoarece faptele sunt reguli
avnd corpul format din scopul true. Aceast reprezentare ne arat c faptele i
regulile au aceeai reprezentare n Prolog (toate reprezint clauze).

MECANISME SPECIFICE

67

Exemplu. Pentru urmtorul predicat:


p(1).
p(X) :- X > 2, X < 5.
p(X).
predicatul clause d urmtoarele rspunsuri:
?- clause(p(X), Corp).
X = 1,
Corp = true ;
Corp = (X > 2, X < 5) ;
Corp = true ;
No

asserta(Clauza), assertz(Clauza), assert(Clauza),


Predicatul asserta(Clauza) reuete ntotdeauna o singur dat i are ca
efect lateral adugarea clauzei Clauza la nceputul bazei de cunotine Prolog.
Predicatele assertz(Clauza) i assert(Clauza) au o comportare similar, cu
excepia faptului c argumentul Clauza este adugat la sfritul bazei de
cunotine. Argumentul Clauza trebuie s fie instaniat la o valoare ce reprezint o
clauz Prolog. Aciunea de adugare a unei clauze prin asserta, assert sau assertz
nu este eliminat de procesul de backtracking. Clauza adugat va fi eliminat
numai n urma unei cereri explicite prin intermediul predicatului retract.

retract(Clauza)
Predicatul retract(Clauza) are ca efect eliminarea din baza de cunotine a
unei clauze, care unific cu argumentul Clauza. Predicatul reuete dac o astfel
de clauza exista; la fiecare resatisfacere se elimin din baza de cunotine o nou
clauz, care unific cu argumentul. Clauza trebuie sa fie argument instaniat la
apel. Odat ce o clauz este eliminat din baza de cunotine prin retract, clauza
nu va mai fi readaugat, dac se face backtracking pe retract.
Exemplu.
adaug :- asserta(prezent(nero)), asserta(prezent(cezar)).
scot :-retract(prezent(nero)).
actiune1 :- adaug, listc(prezent(X)).
actiune2 :- scot, listc(prezent(X)).
?- actiune1.
prezent(cezar).

68

CAPITOLUL 4

prezent(nero).
Yes
?- actiune2.
prezent(cezar).
Yes
Utiliznd predicatul retract, se poate defini un predicat care are rolul de a
elimina din baza de cunotine toate clauzele care definesc un predicat. Acest
predicat, numit retractall(Antet), este predefinit n anumite implementri Prolog.
Definiia lui pe baza predicatului retract este:
% retractall(Antet) - elimin toate clauzele care definesc scopul Antet
retractall(Antet) :- retract(Antet), fail.
retractall(Antet) :- retract( (Antet :- Corp) ), fail.
retractall( _ ).
Observaie: n SWI-Prolog, atunci cnd se adaug/elimin o regul n/din baza de
date n mod dinamic cu assert/retract, regula trebuie pus ntre paranteze rotunde
sau dat ca o structur:
assert( (p(X) :- X=1 ; X=2) ).
retract( ':-'(p(X), ';'(X=1, X=2))).
n definirea scopului p s-a utilizat simbolul ;. Acesta este un operator
predefinit n Prolog, care marcheaz o disjuncie de scopuri, deci are semnificaia
de disjuncie logic. Efectul operatorului ; poate fi reprezentat n urmtorul fel:
X ; Y :- X.
X ; Y :- Y.
Deci aa cum operatorul Prolog , corespunde unei conjuncii de scopuri,
operatorul ; corespunde unei disjuncii de scopuri.
Predicatele asserta, assertz i retract pot fi utile n diverse situaii datorit
efectelor lor laterale. Ele pot simula, de exemplu, un fel de mecanism de variabile
globale n Prolog. Se consider exemplul de implementare a unui generator de
numere aleatoare n Prolog. Se definete predicatul aleator(R, N), care genereaz
un numr aleator N n intervalul [1..R], pornind de la o smn fixat i folosind
metoda congruenei liniare. De fiecare dat cnd trebuie generat un numr aleator,
valoarea acestuia este determinat folosind smna existent i o nou smn
este calculat i memorat ca fapt Prolog pn la noul apel. Vechea smn este
eliminat din baza de cunotine .

MECANISME SPECIFICE

69

% aleator(R, N) - instantiaza N la un numar aleator intre 1 si R


init :- assert(samanta(11)).
aleator(R, N) :samanta(S),
modul(S, R, N1),
N is N1 + 1,
retract(samanta(S)),
N2 is (125 * S +1),
modul(N2, 4096, SamantaNoua),
asserta(samanta(SamantaNoua)).
modul(X, Y, X) :- X < Y.
modul(X,Y,Z) :% Predicatul modulo este predefinit
X >= Y,
% in anumite implementari
X1 is X - Y,
modul(X1, Y, Z).
nainte de apelul predicatului aleator, se apeleaz, o singur dat, predicatul
init, pentru a iniializa smna. La apelul predicatului aleator se obin
urmtoarele rezultate:
?- aleator(100, N).
N = 12
?- aleator(100, N).
N = 77
?- aleator(100, N).
N = 66
Dac se dorete afiarea continu a numerelor aleatoare, o prim variant
este aceea de a crea un ciclu infinit de afiare a acestor numere, efect realizat de
predicatul nr_aleat(R) care afieaz numere aleatoare n intervalul [1..R].
% nr_aleat(R) - afiseaza la infinit numere aleatoare intre 1 si R
nr_aleat(R) :- repeat, aleator(R, X), write(X), nl, fail.
Predicatul fail introdus n definiia predicatului nr_aleat(R) determin
intrarea n procesul de backtracking i datorit predicatului repeat, cele dou
scopuri aleator(R, X) i write(X) se vor satisface la infinit. Trebuie observat
faptul c numai scopul repeat se resatisface; scopurile aleator i write sunt la
prima satisfacere de fiecare dat.
n cazul n care se dorete construirea unui ciclu care se va termina dac o
anumit condiie este ndeplinit, se poate reformula predicatul de generare a
numerelor aleatoare astfel:

70

CAPITOLUL 4

nr_aleat1(R) :repeat, aleator(R, X), write(X), nl,


write('Continuati? [d/n]'), read('n').
Apelnd predicatul, se va obine urmtoarea secven de numere aleatoare:
?- nr_aleat1(10).
2
Continuati? [d/n] d.
7
Continuati? [d/n] d.
6
Continuati? [d/n] n.
Yes

functor(Term, Funct, N)
Predicatul reuete dac cele trei argumente unific astfel: Term este o
structur cu functor Funct i aritate N. Predicatul poate fi folosit n dou moduri:
(1)

Term este argument instaniat i predicatul reuete dac Term


este atom sau structur i eueaz n caz contrar. n caz de succes,
Funct i N sunt instaniate la functorul, respectiv aritatea lui
Term. Un atom este considerat ca fiind o structur de aritate 0.

(2)

Term este argument neinstaniat, iar Funct i N sunt instaniate,


specificnd functorul i numrul de argumente. n acest caz, scopul
reuete ntotdeauna i Term va fi instaniat la o structur cu
functorul i numrul de argumente specificate. Argumentele
structurii construite n acest mod sunt neinstaniate.

Exemple:
?- functor(auto(honda, culoare(rosie)), Funct, N).
Funct = auto,
N=2
?- functor(a + b, F, N).
F = +,
N=2
?- functor(albastru, F, N).
F = albastru,
N=0
?- functor ([a, b, c], !, 3).
No

MECANISME SPECIFICE

71

?- functor(Term, pasi_plan, 3).


Term = pasi_plan(_G405, _G406, _G407)

arg(N, Term, Arg)


Predicatul arg(N, Term, Arg) are ca efect obinerea celui de al N-lea
argument al unei structuri Term, acest argument devenind instanierea lui Arg. N
i Term trebuie s fie argumente instaniate. Arg poate fi instaniat, caz n care
predicatul reuete dac Arg este argumentul N din structura Term, sau Arg poate
fi neinstaniat, caz n care se va instania la cel de al N-lea argument al lui Term.
?- arg(2, poseda(mihai, frumoasa(portocala)), Arg).
Arg = frumoasa(portocala)
?- arg (2,[a, b, c], X).
X = [b, c]
?- arg(1, a + (b + c), b).
No

Scop = .. [Functor | ListArg]


Predicatul =.., numit univ, este un predicat folosit ca operator infixat. El
poate fi folosit n trei moduri:
(1)

Scop este instaniat. n acest caz predicatul reuete, dac Scop


este o structur, iar Functor i ListArg se instaniaz la functorul,
respectiv lista argumentelor acelei structuri.

(2)

Scop este neinstaniat, iar Functor i ListArg sunt instaniate la


un functor, respectiv la o list de argumente a unei structuri. Dac
valorile lui Functor i ListArg sunt corecte, predicatul reuete i
Scop va fi instaniat la structura creat cu functorul i lista de
argumente date.

(3)

Toi trei parametrii sunt instaniati i predicatul reuete, dac


Functor i ListArg sunt functorul, respectiv lista argumentelor
structurii Scop.

Acest predicat are o importan deosebit n Prolog, deoarece el permite


sinteza dinamic a scopurilor Prolog, deci construirea de clauze pe parcursul
execuiei programului. Lucrul acesta este posibil deoarece clauzele Prolog au tot
forma unor structuri alctuite din functor i argument, sintaxa codului fiind aceeai
cu sintaxa datelor n Prolog.

72

CAPITOLUL 4

Exemple:
?- sir(a, b, c) =.. X.
X = [sir, a, b, c]
?- (f(a) + g(b)) =.. [+, f(X), Y].
X = a,
Y = g(b)
?- a + b + c =.. L.
L=[+, a+b, c]

% a + b + c = '+'(a, '+'(b, c))

?- a * b + c =.. L.

% a * b + c = '+'('*'(a, b), c)

L = [+, a * b, c]
?- a + b * c =.. L.

% a + b * c = '+'(a, '*'(b, c))

L = [+, a, b * c]
?- Scop =.. [parinte, mihai, gina].
Scop = parinte(mihai, gina)
?- Scop =.. [membru, a, [a, b, c]].
Scop = membru(a, [a, b, c])
?- conc([1, 2], [3], [1, 2, 3]) =.. [Functor | ListArg]
Functor = conc,
ListArg = [[1, 2], [3], [1, 2, 3]]
?- S =.. [f, X, a,Y].
S = f(X, a, Y)
?- f =.. L.
L = [f]
Folosind univ putem verifica faptul c listele se reprezint prin structuri cu
punct de forma: '.'(PrimulElement, RestulListei). Lista [1, 2] este totuna cu
'.'(1, [2]) sau cu '.'(1, '.'(2, [])).
Exemplu.
?- [1,2] =.. L.
L = ['.', 1, [2]]

listing, listing(+Nume), listing(+Nume/Aritate),


listing(+[Nume/Aritate])

MECANISME SPECIFICE

73

Predicatul listing tiprete din baza de cunotine toate clauzele, toate


clauzele unui predicat sau toate clauzele unor predicate dintr-o list. De exemplu,
pentru predicatele:
p.
p(1).
p(X) :- X > 2, X < 5.
p(X).
p(1,2).
p(X,Y) :- X < Y.
se pot face urmtoarele interogri (redenumirile variabilelor sunt fcute automat de
sistem):
?- listing(p/1).
p(1).
p(A) :A > 2,
A < 5.
p( _ ).
Yes
?- listing([p/0, p/2]).
p.
p(1,2).
p(A, B) :A < B.
Yes

4.2.4

Predicate pentru execuia dinamic a scopurilor


call(Scop)

Se presupune c argumentul Scop este instaniat la un scop Prolog.


Predicatul call(Scop) reuete dac Scop reuete i eueaz n caz contrar. La
prima vedere acest predicat pare redundant, deoarece execuia scopului Scop se
poate face direct n Prolog. Dac se doreste execuia dinamic a scopurilor care au
fost sintetizate pe parcursul execuiei unui program Prolog, atunci predicatul call
este necesar. n plus, dac nu se cunoate scopul de executat, de exemplu se
dorete execuia a diverse scopuri cu argumente diferite sau cu aceleai argumente,
se poate folosi predicatul call cu argument o variabil, care se va instania n
funcie de ntrebarea utilizatorului sau de context.

74

CAPITOLUL 4

Execuia dinamic a scopurilor poate fi exprimat prin urmtoarea secven


de scopuri:
... obine(Functor), calculeaz(ArgList), Scop =.. [Functor | ArgList],
call(Scop), ...
Se prezint n continuare diverse variante de predicate Prolog care aplic un
predicat primit ca argument fiecrui element al unei liste sau al mai multor liste,
rezultatele fiecrei aplicri fiind cumulate ntr-o list rezultat. Acest tip de
predicate reprezint o categorie de prelucrri ale listelor, frecvent ntlnite i
necesare.
Se definete nti predicatul mapcar(Pred, ListaArg, ListaRez), care
primete dou argumente instaniate Pred i ListaArg i calculeaz ListaRez.
Pred este un predicat Prolog care are la rndul lui dou argumente: primul,
instaniat, este folosit n prelucrare pentru obinerea celui de al doilea i este
obinut ca element curent din ListaArg; cel de al doilea, neinstaniat, este calculat
de Pred i este depus ca element curent n ListaRez. n programul care urmeaz se
vor folosi ca predicate Pred urmtoarele:
prim(Lista, El) care obine primul element dintr-o list,
neg(Element, -Element) care schimb semnul unui element i
adaug(Nume, NumeFrumos) care adaug n faa unui nume apelativul
de politee dna dac persoana este femeie i dl dac persoana este brbat.
Se observ c argumentele lui Pred din definiia lui mapcar pot fi att
elemente atomice (atomi sau numere), ct i liste.
% Se definesc predicatele de prelucrare a listelor: mapcar, mapcar2 si
mapcarnl.
prim([], []).
prim([X | _ ], X).
neg(X, Y) :- Y is -1 * X.
adaug(Nume, NumeFrumos) :write(Nume),
write(' este femeie sau barbat (f/b)? '),
read(Sex),
(Sex = b, NumeFrumos = [dl, Nume] ;
Sex = f, NumeFrumos = [dna, Nume]).
% mapcar(Pred, ListaArg, ListaRez) - evalueaza predicatul
% Pred pentru fiecare element din lista ListaArg si
% construieste rezultatul in ListaRez.
% Predicatul Pred are doua argumente, atomice sau liste.

MECANISME SPECIFICE

75

mapcar( _ , [], []).


mapcar(P, [Arg | RestArg], [X | Rest]) :Scop =.. [P, Arg, X],
call(Scop),
mapcar(P, RestArg, Rest).
Comportarea acestui program este urmtoarea:
?- mapcar(prim, [[alain, turing], [ada, byron]], Rez).
Rez = [alain, ada]
?- mapcar(neg, [1, 2, 3, 4], Rez).
Rez = [-1, -2, -3, -4]
?- mapcar(adaug, [maria, mihai, george, ana], Rez).
maria este femeie sau barbat (f/b)? f.
mihai este femeie sau barbat (f/b)? b.
george este femeie sau barbat (f/b)? b.
ana este femeie sau barbat (f/b)? f.
Rez = [[dna, maria], [dl, mihai], [dl, george], [dna, ana]]
Dac se dorete execuia unor prelucrri similare, dar pentru predicate
Prolog care admit trei argumente, primele doua instaniate i cel de al treilea
sintetizat de predicatul Pred pe baza primelor dou, se poate defini de o maniera
similar predicatul:
mapcar2(Pred, ListaArgPrim, ListaArgSecund, ListaRez)
Se va demonstra funcionarea acestui predicat n cazurile n care predicatul
Pred, care se mapeaz pe elementele listelor ListaArgPrim i ListaArgSecund,
este nti adun(A, B, Rez), care calculeaz n Rez suma lui A i B, apoi
conc(List1, Lista2, ListaRez), care concateneaz dou liste i depune rezultatul n
ListaRez. Argumentele predicatului Pred pot fi argumente atomice sau liste.
conc([], L, L).
conc([X|Rest], L, [X|Rest1]) :- conc(Rest, L, Rest1).
adun(A, B, Rez) :- Rez is A + B.
% mapcar2(Pred, ListaArgPrim, ListaArgSecund, ListaRez) % evalueaza predicatul Pred pentru fiecare pereche
% de argumente, unul din ListaArgPrim, celalalt din ListaArgSecund
% si construieste rezultatul in ListaRez.
% Predicatul Pred are trei argumente, atomice sau liste.
mapcar2( _ , [], _ , []).
mapcar2(P, [Arg1 | RestArg1], [Arg2 | RestArg2], [X | Rest]) :Scop =.. [P, Arg1, Arg2, X],
call(Scop), mapcar2(P, RestArg1, RestArg2, Rest).

76

CAPITOLUL 4

?- mapcar2(adun, [1, 2, 3, 4], [10, 20, 30, 40], Rez).


Rez = [11, 22, 33, 44]
?- mapcar2(conc, [[1, 2], [a, b]], [[3, 4], [c, d]], Rez).
Rez = [[1, 2, 3, 4], [a, b, c, d]]
Se observ c este necesar definirea unui predicat de tip mapcar diferit
pentru fiecare categorie de aritate N a predicatelor care pot instania legal Pred.
Dac se impune restricia conform creia predicatul Pred poate avea numai
argumente
atomice,
atunci
se
poate
defini
predicatul
mapcarnl(Pred, ListaListeArg, ListaRez) cu un efect similar. ListaListeArg
este fie o list de elemente atomice, dac Pred are dou argumente, dintre care
primul instaniat va fi obinut ca elementul curent al acestei liste, fie o list de
liste, unde fiecare element list din ListaListeArg conine primele N-1 argumente
atomice ale lui Pred.
% mapcarnl(Pred, ListaListeArg, ListaRez) % evalueaza predicatul Pred cu primele N-1 argumente din lista
% ListaListeArg si construieste rezultatul in ListaRez.
% Predicatul Pred poate avea oricate argumente, dar toate trebuie sa fie
% atomice.
mapcarnl(_, [], []).
mapcarnl(P, [Arg|RestArg], [X|Rest]) :(atomic(Arg), FormaScop = [P,Arg,X] ;
not(atomic(Arg)), conc([P], Arg, Temp),
conc(Temp, [X], FormaScop)), Scop =.. FormaScop,
call(Scop), mapcarnl(P, RestArg, Rest).
?- mapcarnl(neg, [1, 2, 3, 4], Rez]
Rez = [-1, -2, -3, -4]
?- mapcarnl(adun, [[1, 10], [2, 20], [3, 30], [4, 40]], Rez).
Rez = [11, 22, 33, 44]

findall(X, Scop, Lista)


Predicatul findall(X, Scop, Lista) are ca efect obinerea tuturor termenilor
X care satisfac predicatul Scop n baza de cunotine a programului i cumularea
acestor termeni n lista Lista. Scop trebuie s fie instaniat la un predicat Prolog n
care, n mod normal, trebuie s apar X. Dac Scop nu reuete, findall reuete,
instaniind Lista la lista vid.
Exemple:
prieten(vlad, ana).
prieten(vlad, george).

MECANISME SPECIFICE

77

prieten(vlad, mihai).
prieten(liviu, ana).
?- findall(X, prieten(vlad, X), L).
L = [ana, george, mihai]
Efectul predicatului findall poate fi explicat i prin definiia explicit a unui
predicat cu acelai efect: find_all(X, Scop, Lista)
% find_all(Arg, Scop, Lista) % are acelasi efect ca predicatul standard findall(Arg, Scop, Lista).
prieten(vlad, ana).
prieten(vlad, george).
prieten(vlad, mihai).
prieten(liviu, ana).
find_all(X, S, _) :-

asserta(stiva(baza_stivei)),
call(S),
% Scopul S contine X.
asserta(stiva(X)), fail.
find_all( _ , _ , L) :- colecteaza([], M), !, L = M.
colecteaza(S, L) :colecteaza(L, L).

urmator(X), !, colecteaza([X | S], L).

urmator(X) :- retract(stiva(X)), !, X \= baza_stivei.


?- find_all(X, prieten(vlad, X), L).
L = [ana, george, mihai]
?- find_all(X, prieten(toma, X), L).
L = []
n definiia predicatului find_all se observ folosirea unei tehnici de
programare Prolog interesante. Utiliznd predicatul asserta se simuleaz o
structur de stiv n Prolog. Baza stivei este marcat de faptul stiva(baza_stivei) i
n stiv se introduc, ca fapte suplimentare adugate la nceputul bazei de
cunotine Prolog, valorile X care satisfac scopul S sub forma stiva(X), cu X
instaniat de apelul call(S). Acest lucru este executat pentru toate soluiile posibile
ale predicatului call(S), datorit predicatului fail introdus n finalul definiiei
primei clauze a predicatului find_all. n acest fel, toate valorile lui X din baza de
cunotine Prolog, care satisfac S, sunt introduse n stiva simulat. Cea de a doua
clauz a predicatului find_all, care se execut dup ce nu mai exist nici o
posibilitate de resatisfacere a primei clauze, are ca scop golirea stivei i colectarea
valorilor introduse n stiv, pn la baza ei, stiva(baza_stivei), n lista M.

78

CAPITOLUL 4

bagof(X, Scop, Lista)


Predicatul bagof(X, Scop, Lista) are ca efect colectarea n Lista a tuturor
termenilor X care satisfac Scop, innd cont de diversele instanieri posibil diferite
ale celorlalte variabile din Scop. Scop este un argument, care trebuie s fie
instaniat la un scop Prolog. Dac Scop nu conine alte variabile n afara lui X,
atunci efectul predicatului bagof este identic cu cel al lui findall. Dac Scop nu
reuete cel puin o dat atunci bagof eueaz.
Exemple:
clasificare(a, vocala).
clasificare(b, consoana).
clasificare(c, consoana).
clasificare(d, consoana).
clasificare(e, vocala).
clasificare(f, consoana).
?- findall(X, clasificare(X, C), L).
L = [a, b, c, d, e, f]

% o soluie

?- bagof(X, clasificare(X, C), L).


C = vocala,
L = [a, e];
C = consoana,
L = [b, c, d, f];
No

% dou soluii

setof(X, Scop, Lista)


Predicatul setof(X, Scop, Lista) are acelai efect cu predicatul bagof, cu
excepia faptului c valorile cumulate n lista Lista sunt sortate cresctor i se
elimin apariiile multiple de valori, deci Lista devine o mulime ordonat. Dac
Scop nu reuete cel puin o dat, atunci setof eueaz.
Considernd faptele de definire a consoanelor i variabilelor prezentate
anterior, se poate construi urmtorul exemplu, n care mai introducem dou fapte:
clasificare(e, vocala).
clasificare(d, consoana).
?- bagof(X, clasificare(X, C), L).
C = vocala,
L = [e, a, e];
% vocala e apare de dou ori

MECANISME SPECIFICE

79

C = consoana,
L = [d, b, c, d, f];
% consoana d apare de dou ori
No
?- setof(X, clasificare(X, C), L).
C = vocala,
L = [a, e];
% vocalele apar o singur dat
C = consoana,
L = [b, c, d, f];
% consoanele apar o singur dat
No

4.3

Operatori definii de utilizator

Limbajul Prolog permite definirea de noi operatori de ctre programator, prin


introducerea n program a unor clauze de form special, numite directive.
Directivele acioneaz ca o definire de noi operatori ai limbajului, n care se
specific numele, precedena i tipul (infixat, prefixat sau postfixat) operatorului.
Se reamintete faptul c orice operator Prolog este de fapt o structur, care are ca
functor numele operatorului i ca argumente, argumentele operatorului, dar este
scris ntr-o sintax convenabil. La definirea de noi operatori n Prolog, se creeaz
de fapt noi structuri, crora le este permis o sintax special, conform definiiei
corespunztoare a operatorului. Din acest motiv, nu se asociaz nici o operaie
operatorilor definii de programator. Operatorii noi definii sunt utilizai ca
functori, numai pentru a combina obiecte n structuri i nu pentru a executa aciuni
asupra datelor, dei denumirea de operator ar putea sugera o astfel de aciune.
De exemplu, n loc de a utiliza structura:
are(coco, pene)
se poate defini un nou operator are
:- op(600, xfx, are).
caz n care este legal expresia
coco are pene.
Definirea de noi operatori se face cu ajutorul directivei:
:- op(preceden-operator, tip-operator, nume-operator).
Operatorii sunt atomi, iar precedena lor trebuie s fie o valoare ntreag
ntr-un anumit interval i corelat cu precedena operatorilor predefinii n limbaj.

80

CAPITOLUL 4

Tipul operatorilor fixeaz caracterul infixat, prefixat sau postfixat al operatorului


i precedena operanzilor si. Tipul operatorului se definete utiliznd una din
urmtoarele forme standard:
(1) operatori infixai:

xfx xfy yfx

(2) operatori prefixai:

fx

fy

(3) operatori postfixai:

xf

yf

unde f reprezint operatorul, iar x i y operanzii si. Utilizarea simbolului x sau a


simbolului y depinde de precedena operandului fa de operator. Precedena
operanzilor se definete astfel:

un argument ntre paranteze sau un argument nestructurat are precedena


0;

un argument de tip structur are precedena egal cu cea a functorului


operator.
Observaie: n SWI-Prolog, cu ct valoare-preceden-operator este mai mare,
cu att operatorul are o preceden mai mic i invers.
Semnificaiile lui x i y n stabilirea tipului operatorului sunt urmtoarele:

x reprezint un argument (operand) cu preceden strict mai mic dect


cea a functorului (operatorului) f
precedena( x ) < precedena( f )

y reprezint un argument (operand) cu preceden mai mic sau egal cu


cea a functorului (operandului) f
precedena( y ) precedena( f )
Aceste reguli ajut la eliminarea ambiguitii operatorilor multipli cu
aceeai preceden. De exemplu, operatorul predefinit n Prolog - (minus) este
definit din punct de vedere al tipului ca yfx, ceea ce nseamn c structura a - b - c
este interpretat ca (a - b) - c i nu ca a - (b - c) . Dac acest operator ar fi fost
definit ca xfy, atunci interpretarea structurii a - b - c ar fi fost a - (b - c) .
Numele operatorului poate fi orice atom Prolog, care nu este deja definit n
Prolog. Se poate folosi i o list de atomi, dac se definesc mai muli operatori cu
aceeai preceden i acelai tip.
Exemple:
:- op(100, xfx, [este, are]).
:- op(100, xf, zboara).
coco are pene.

MECANISME SPECIFICE

81

coco zboara.
coco este papagal.
bozo este pinguin.
?- Cine are pene.
Cine = coco
?- Cine zboara.
Cine = coco
?- Cine este Ce.
Cine = coco,
Ce = papagal;
Cine = bozo,
Ce = pinguin;
No
n condiiile n care se adaug la baza de cunotine anterioar i definiia
operatorilor daca, atunci i si
:- op(870, fx, daca).
:- op(880, xfx, atunci).
:- op(880, xfy, si).
urmtoarea structur este valid n Prolog:
daca Animalul are pene
i Animalul zboara
atunci Animalul este pasare.
Notaia cu operatori permite programatorului s ajusteze sintaxa
programelor conform propriilor dorine. nelegerea programelor este mult
mbuntit atunci cnd se folosesc operatori.
Exemplu: Dac definim operatorii joaca i si:
:- op(300,xfx, joaca).
:- op(200, xfy, si).
atunci urmtorii termeni sunt obiecte legale din punct de vedere sintactic:
Termen1 = tom joaca fotbal si tenis.
Termen2 = susan joaca tenis si volei si ping-pong.
Calculele aritmetice sunt fcute prin proceduri predefinite. Evaluarea unei
expresii aritmetice este forat de procedura is i de predicatele de comparaie <,
=<, etc. De exemplu:

82

CAPITOLUL 4

?- X = 3 / 2
X=3/2
?- X is 3 / 2
X = 1.5

4.4

Exerciii propuse

EP1. Fie urmtorul program Prolog:


este(a).
este(b).
este(c).
exista(X) :- este(X) ; true.
Cte soluii are fiecare dintre urmtoarele scopuri:
?- exista(A), exista(B), exista(C), A \= a, B \= b, C \= c.
?- exista(A), exista(B), exista(C), !, A \= a, B \= b, C \= c.
?- exista(A), !, exista(B), exista(C).
EP2. S se scrie un predicat, care citete n bucl numere i rspunde dac sunt
prime sau nu, pn la ntlnirea unui numr negativ, folosind predicatul predefinit
repeat.
EP3. S se scrie un program care calculeaz numrul de zile dintre dou date
exprimate sub forma Zi-Luna, presupunnd c datele se refer la acelai an.
Caracterul - se va defini ca un operator infixat.
Ex: interval(3-martie, 7-aprilie, I) produce I = 35.
EP4. S se scrie un program care citete propoziii simple (afirmaii i ntrebri, pe
care le adaug n baza de cunotine Prolog), avnd una din formele:
_ este un _.
_ este o _.
Un _ este un/o _.
O _ este un/o _.
Este _ un/o _ ?
i rspunde adecvat (da, nu sau necunoscut) la ntrebri pe baza afirmaiilor
introduse. Exemplu: Radu este un student. Un om este o fiin. Radu este un om.
Este Maria o persoan?

MECANISME SPECIFICE

83

EP5. S se defineasc operatorii Prolog este, are, un etc. astfel nct s poata fi
introduse clauze de forma:
diana este secretara lui toma.
maria are un pian.
i sistemul s poata rspunde la ntrebri de tipul:
?-Cine este secretara lui toma.
Cine=Diana
?-diana este Ce.
Ce=secretara lui toma
?-maria are un Ce.
Ce=pian
EP6. S se scrie un program Prolog de evaluare a unei expresii aritmetice care
conine variabile, constante ntregi, paranteze i operatorii: +, -, *, /. Valorile
variabilelor sunt date sub forma de fapte Prolog, prin predicatul
valoare(Variabila, Valoare); de exemplu valoare(x, 100) sau valoare(y, -50).
EP7. S se scrie un program care determin negarea unei formule n logica cu
propoziii. Conectorii logici considerai sunt: not, and, or i implies. S se dea
definiii adecvate pentru aceti operatori.
Ex: neaga(p implies (q and not r),E) va produce E = p and (not q or r)
EP8. Utiliznd predicatul bagof, scriei predicatul parti_mult(Mult, Submult)
care calculeaz n Submult mulimea submulimilor mulimii Mult. Reprezentai
mulimile sub form de liste.