Cap 4 Mecanisme FN

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 situaţii deosebit de util, dar poate deveni foarte ineficient în alte situaţii. Se consideră următorul exemplu de program, în care se definesc valorile unei funcţii: 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 răspunde indicând că valoarea funcţiei pentru X=1 este Y=0. Dacă se pune întrebarea formată din conjuncţia de scopuri: ?- f(1, Y), 2 < Y. No sistemul semnalează eşec. Arborii de deducţie corespunzători acestor răspunsuri sunt prezentaţi în figura 4.1. Se observă că se încearcă resatisfacerea primului scop cu regulile 2 şi 3, deşi acest lucru este evident inutil, datorită semanticii acestor reguli. Cel care a scris aceste reguli poate cu uşurinţă constata că, dacă o valoare mai mică decât 3 pentru X duce la eşecul scopului S din conjuncţia 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.

description

4

Transcript of Cap 4 Mecanisme FN

  • 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.