-
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. % 1 f(X, 2) :- 3 =< X, X < 6. % 2
f(X, 4) :- 6 =< X. % 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
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.
f(1,Y)
f(1,0)
X=1Y=0
1
-
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, !. % cut verde min1(X, Y, Y) :- X
> Y. min2(X, Y, X) :- X =< Y, !. % cut rou min2(X, Y, Y).
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. % Semnificaia declarativ este: p :- c. % (a b) c %
indiferent de ordinea clauzelor (n general).
-
MECANISME SPECIFICE 57
p :- a, !, b. % Semnificaia declarativ este: p :- c. % (a b) (~
a c). p :- c. % Semnificaia declarativ este: p :- a, !, b. % 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, ?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).
?- max(X, 3, 4). X = 4 X = 4 ?- max(3, X, 4). X = 4 X = 4 ?-
max(X, X, 3). X = 3 X = 3
-
MECANISME SPECIFICE 61
Cazuri n care predicatul max trebuie s eueze:
?- max(X, 3, 2). No No ?- max(3, X, 2). 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. % 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 = '+'(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) :- urmator(X), !, colecteaza([X | S], L).
colecteaza(L, 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
-
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.