Documente Academic
Documente Profesional
Documente Cultură
1/19
2
Limbajul LPAProlog
Istoria programrii logice cuprinde cteva etape reprezentative: 1970 Robert Kowalsky, Edinburgh University i Alain Colmerauer, Universit dAix Marseille au pus bazele unei colaborri cu un obiectiv comun: utilizarea formalismului logicii matematice la definirea unui limbaj de programare. Cercetrile lui R. Kowalsky au constituit cadrul teoretic necesar, iar A. Colmerauer i P. Roussel au scris primul interpretor i au definit limbajul Prolog (PROgrammation LOGique). Primul compilator Prolog (Kowalsky) a fost realizat la Warren Edinburgh University, Department of AI. 1980 Borland a elaborat versiunea Turbo Prolog, implementabil pe IBM PC, ceea ce a dus la rspndirea i cunoaterea limbajului. 1981 Conferina Internaional de IA de la Tokyo: elaborarea celei de-a V-a generaie de calculatoare i a procesoarelor de cunotine orientate pe limbajul Prolog. PVG (Prolog Vendors Group) reunete productorii i utilizatorii limbajului Prolog: Boeing, IBM, Quintus, LPA, Prolog IA. William Clocksin i Christopher Mellish public n 1981 cartea Programming in Prolog, care definete standardul Edinburgh al limbajului Prolog. Standardul Borland este mai restrictiv referitor la posibilitile de calcul simbolic. LPA (London Prolog Associates) elaboreaz LPA Prolog, care are la baz standardul Edinburgh, dar aduce i o serie de dezvoltri proprii (metapredicate).
Cele prezentate n cele ce urmeaz se refer la versiunea LPA Prolog, ce constituie totodat i suportul aplicaiilor prezentate. Implementarea LPA deriv din mai bine cunoscuta versiune Edinburgh Prolog, creia firma londonez productoare (London Prolog Associates) i-a adus mbuntiri i dezvoltri suplimentare (metapredicate, faciliti grafice etc.). Versiunea de referin Edinburgh Prolog a fost definit de W.F.Clocksin i C.S.Mellish n cartea Programming in Prolog, lucrare considerat la ora actual un standard neoficial al limbajului Prolog. Prolog este un limbaj declarativ, spre deosebire de alte limbaje (C, Pascal, Basic etc.) care sunt procedurale (descriu modul de rezolvare a problemelor).
IASE
2/19
Comentariile. Pentru documentare, ntr-un program Prolog se pot introduce oricnd comentarii. n funcie de ntinderea (amploarea) acestora, exist dou modaliti de introducere a comentariilor. Caracterul % definete drept comentariu coninutul liniei, ncepnd cu caracterul nsui i pn la sfritul acesteia. Inserarea unui comentariu pe mai multe rnduri se face ncadrnd textul respectiv ntre delimitatorii /* i */.
IASE
3/19
exemplu termenul 0d desemneaz numrul ntreg 100, care este codul ASCII al caracterului d. Atomii. Atomii sunt denumiri alfanumerice sau simbolice prin care programatorul poate desemna obiecte, proprieti ale acestora, precum i diverse relaii stabilite ntre acestea. Lungimea maxim a unui atom este de 255 de caractere. Exist patru tipuri de atomi: alfanumerici, simbolici, de tip ir de caractere i atomi rezervai. Atomi alfanumerici. Un atom alfanumeric este format dintr-o liter mic (a-z) urmat de o secven format din zero sau mai multe litere (a-z, A-Z) sau cifre (0-9). Caracterele din jumtatea superioar a tabelei ASCII sunt considerate litere mici. Utilizarea acestor caractere nu este ns recomand din motivele deja menionate la descrierea alfabetului. Urmtorii termeni sunt coreci i reprezint atomi alfanumerici: mar cristy michael bmw a123 Atomi simbolici. Un atom simbolic este format dintr-o secven format din unul sau mai multe din caracterele speciale enumerate mai jos: # $ & = ^ ~ \ @ ; / + * ? < > sau din caractere din partea superioar a tabelei ASCII. Urmtorii termeni & && + ++ << >> -> <*/* <$> constituie exemple corecte de atomi simbolici. Atomi de tip ir. Un atom de tip ir sau quoted atom este o succesiune de caractere cuprins ntre apostrofuri. Dac se dorete inserarea unui apostrof n cadrul irului de caractere, atunci apostroful se dubleaz. Caracterul ~ (tilda) poate fi utilizat pentru definirea unor caractere speciale sau de control. De exemplu termenul ~<Liter> semnific caracterul <Ctrl> <Liter>, n timp ce termenul ~<Numr> reprezint caracterul al crui cod ASCII este <Numr>, Numr{0,1,,255}. Atomi rezervai. Atomii simbolici enumerai mai jos ! ; [] {} = :au o semnificaie prestabilit n cadrul limbajului i nu pot fi utilizai pentru denumirea unor entiti utilizator. irurile de caractere. Un ir de caractere este o succesiune de caractere cuprins ntre apostrofuri invers nclinate (caracterul `). Dei irurile de caractere sunt considerate termeni simpli, deci de tip atomic (vezi tabelul 1), acestea nu sunt considerate atomi i nu trebuie confundate cu atomii quoted. Pentru a nu crea confuzii de acest tip, n cele ce urmeaz, pentru a desemna termenii de acest tip se va utiliza termenul strig. Deosebirea dintre un termen de tip string i un quoted atom const n primul rnd n modul intern de reprezentare al acestora. n plus, termenii de tip string pot fi supui unor operaii proprii irurilor de caractere. Exist totui posibilitatea (predicatul atom_string/2) de a se realiza conversia de la atom la tipul string i reciproc. Termenii compui. Un termen compus are urmtoarea sintax: functor(t1,t2,, tn) , unde functor este un atom (de oricare din cele trei tipuri descrise mai sus), iar argumentele t1,t2,,,tn sunt termeni, care pot fi simpli sau structurai la rndul lor. Functorul definete practic modul de structurare al termenului respectiv. Avnd n vedere faptul c numrul de argumente al functorului este variabil, iar gradul de imbricare este teoretic nelimitat, un termen compus poate reprezenta practic orice structur relaional de date, indiferent de gradul de complexitate al acesteia. n sintaxa imbricat a unui termen compus, functorul cel mai exterior este denumit functor principal. Urmtoarele construcii sintactice reprezint exemple corecte de termeni compui: a(b,c(d,e(f,g))) alfa(X,Y) color(blue,yellow) +++(<<,>>,ok) Un termen compus are urmtoarea sintax:
4/19 ( termen
, Functorul cel mai exterior se numete functor principal. Fiecrui termen i este asociat o aritate (numrul de argumente). Termenii simpli au aritatea = 0, iar cei compui au aritatea 1. Este a+b un termen Prolog? Da, +(a,b) este un termen Prolog de tip infix i aritate 2. Structura descris de un termen compus poate fi ilustrat grafic prin reprezentarea acesteia sub forma unui arbore. Astfel, functorul principal va reprezenta i eticheta rdcina arborelui, care va avea un numr de descendeni egal cu aritatea (numrul de argumente) functorului respectiv, fiecare dintre acetia corespunznd unuia din argumentele sale. Dac argumentul este un termen simplu, nodul corespunztor va constitui o frunz a arborelui, iar n caz contrar functorul respectiv va eticheta rdcina unui subarbore construit n maniera recursiv astfel definit. De exemplu, primul dintre termenii citai mai sus se poate reprezenta printr-un arbore a crui mulime de noduri este {a,b,c,d,e,f,g} i a crui mulime de muchii este {[a,b],[a,c],[c,d],[c,e],[e,f],[e,g]}, nodul a fiind rdcina, iar b,d,f i g nodurile terminale sau frunzele arborelui respectiv. Observaie. Un arbore este de fapt un graf neorientat, deci oricare dintre noduri poate fi considerat rdcina arborelui. Totui, avnd n vedere situaia de fa nodul corespunztor functorului principal va fi considerat rdcina arborelui. Liste. O list este o secven format dintr-un numr oarecare de elemente. O list se poate reprezenta n Prolog enumernd, ntre paranteze ptrate, elementele sale componente separate prin virgul. De exemplu, urmtorii termeni sunt coreci i reprezint liste: [a,b,c,d] [jerry] [1,2,3,4,5] [a,2,[1,2,3],a(b,c),d] [] Ultima dintre acestea constituie un caz particular i reprezint lista vid (lista fr nici un element). Orice list este compus din cap i coad. Capul este primul element al listei, iar coada este lista format din restul elementelor. De exemplu, prima din listele citate mai sus are capul a i coada [b,c,d], iar cea de a doua are capul jerry i coada []. Lista vid nu se poate descompune n cap i coad. Listele sunt de fapt cazuri particulare de termeni compui i au o aplicabilitate deosebit n limbajele de programare orientate spre calculul simbolic. Functorul care desemneaz o structur de tip list este punctul, iar aritatea acestuia este 2. Primul argument este capul, iar cel de al doilea este coada listei. De exemplu, lista [a,b,c,d] se poate reprezenta, n sintaxa standard Edinburgh Prolog, prin termenul compus .(a,.(b,.(c,.(d,[])))). Atenie, nu se va lsa spaiu ntre punct i paranteza deschis. De fapt acest mod de scriere corespunde modului intern de reprezentare al listei, aceasta fiind de fapt un arbore binar. Dat fiind ns lizibilitatea destul de redus a acestei construcii sintactice, limbajul Prolog accept reprezentarea sub form de enumerare a listelor, dar aceasta reprezint doar un mod de reprezentare extern a acestora. Tot pentru a veni n ajutorul programatorului o list se poate exprima i sub forma: [cap | coad] deci desprind printr-o bar vertical capul listei de coada acesteia. Totodat o list se poate descrie i sub forma: [element1,element2,elementn | coad], dar avnd grij c dup simbolul | trebuie scris o list i nu un element. De exemplu, fiecare din termeni de mai jos este corect i reprezint aceeai list [a,b,c,d]: [a|[a,b,c,d]] [a,b|[c,d]] [a,b,c|[d]] [a,b,c,d|[]] [a|[b|[c|[d]]]] [a,b|[c|[d]]] [a,b,c|[d|[]]] Observaie. Modalitile diverse de reprezentare a listelor permit, graie mecanismului de unificare, extragerea i/sau identificarea elementelor componente ale unei liste. Liste de octei. O list de octei este o succesiune de caractere de orice tip cuprins ntre ghilimele. Structura de date astfel definit const n lista codurilor ASCII ale caracterelor care compun
IASE
5/19
irul. Pentru a insera caracterul n cadrul unei liste acesta se dubleaz. De exemplu termenul: Aceasta este o lista este corect i reprezint lista [65,99,101,97,115,116,97,32,101,115,116,101,32,111,32,108,105,115,116,97]. Ca i n cazul atomilor de tip quoted, caracterul ~(tilda) poate fi utilizat pentru definirea unor caractere speciale, de exemplu termenul ~G reprezint lista [7]. Observaie. Listele de octei nu trebuie confundate cu irurile de caractere sau cu atomii de tip quote, dat fiind faptul c acestea difer sintactic doar prin tipul de apostrofuri utilizate ( ` respectiv ) pentru ncadrarea succesiunii de caractere care le compun. Dei modul de reprezentare, structurile de date aferente i modul de operare cu aceste structuri sunt diferite, limbajul LPA Prolog dispune ns de predicate specifice care permit conversia ntre oricare din cele trei tipuri (quoted atomi, iruri de caractere, liste de octei). Tabelul 1. Termenii limbajului Prolog predicat /aritate var /1, nonvar /1 atomi alfanumerici atom /1 atomi simbolici atom /1 quoted atomi atom /1 ntregi numere integer /1 number/1 reale float /1 iruri de caractere string /1 Tipul termenului compound /1
termeni compui
IASE
6/19
Un fapt este de forma: antet. unde, din punct de vedere sintactic, antet este un atom sau un termen compus, al crui functor trebuie s fie diferit simbolul :- sau =. Sintactic, un fapt se termin prin punct, ce trebuie urmat obligatoriu de spaiu sau de terminatorul de sfrit de linie. fapt predicat/0 .
predicat/1
, termen
, Un fapt are sintaxa unui termen i reprezint un predicat, care poate fi de aritate 0 sau orice aritate 1. ntr-un limbaj Prolog, orice functor principal reprezint un predicat. Argumentele oricrui predicat, dac exist, sunt termeni i nu pot fi alte predicate; de aceea, limbajul se numete de ordinul I. O regul este de forma: (1) antet :- t1, t2,,tk. unde antet constituie capul sau concluzia regulii i apare n partea stng a simbolului :-, iar t1, t2,,tk, k1 constituie premisele regulii. Fiecare tk este un predicat sau un termen executabil denumit n limba englez call term sau goal. Regula este terminat printr-un punct urmat de spaiu sau terminatorul de sfrit de linie. Intuitiv, un termen este denumit executabil dac consistena sau valoarea de adevr a acestuia poate fi dedus din contextul clauzelor programului Prolog. Din punct de vedere al logicii matematice, regula (1) este echivalent cu implicaia (virgula are semnificaia de conjuncie logic, iar simbolul :- de implicaie invers): (2) antet t1 t2 tk , deci inferarea concluziei antet se poate face dac, pentru un anumit mod de instaniere a variabilelor din componena acestora, premisele t1, t2,,tk. pot simultan satisfcute. regul predicat :predicat , antet ; . Conjuncie Disjuncie
corpul regulii Pentru a nelege noiunea de termen executabil sau goal trebuie plecat de la premisa c ntr-un program Prolog orice functor principal este un simbol predicativ (predicat) i are n consecin o valoare de adevr. Dac n logica matematic scriem abc, adic ab, scriem ac, n Prolog se obine: a :- b; c. Dpdv matematic, clauzele Prolog sunt clauze Horn pozitive, n cadrul crora variabilele sunt universal cuantificate. Mulimea acestor clauze poart denumirea de Program. Definirea unui fapt de forma: fapt(a1,,ak). presupune specificarea (asertarea) faptului c predicatul fapt(a1,,ak) este adevrat. Astfel faptele permit declararea unor piese de cunoatere presupuse adevrate (date, ipoteze), iar regulile
IASE
7/19
specificarea unor reguli de inferen (axiome, teoreme) prin care pot fi deduse noi fapte sau piese de cunoatere.
IASE
8/19 Interpretorul limbajului Prolog are urmtorul mod de lucru: Program PROLOG P
Goal
Indicatorul yes nseamn c exist o substituie astfel nct din P este deductibil Q (P Q), adic o instan a lui Q este deductibil din P, deci Q este o consecin logic a mulimii P. Indicatorul no nseamn c din P nu este deductibil Q (P Q), adic Q nu este o consecin
logic a mulimii P. n cazul rspunsului yes mecanismul inferenial returneaz substituia . Variabilele instaniate (iniializate) pot fi privite ca parametrii de intrare ai procedurii libere, iar variabilele libere ca parametri de ieire ai procedurii, parametri ce vor fi instaniai cu valorile corespunztoare de interpretorul Prolog . Mulimea clauzelor unui program care corespund unui aceluiai predicat poart numele de procedur. Aceste proceduri sunt mult mai flexibile dect cele din limbajele de programare. O procedur Prolog poate fi aplicat n mai multe moduri (flow pattern), programatorul putnd inversa parametrii de intrare cu cei de ieire. Exemplu: Predicatul p/2 {(i,i), (i,o), (o,i), (o,o)} i input; o output. fata(maria, ion). ?: fata(Cine, Cui). % (o,o) ?: fata(Cine, ion). % (o,i) Cine=maria ?: fata(maria, Cui). % (i,o) Cui=ion ?: fata(maria, ion). % (i,i) yes Fiecare predicat executabil poate fi considerat ca o procedur, n sensul cunoscut din programarea clasic. O procedur mai returneaz i acel indicator de rspuns (yes sau no). Dup ce un program Prolog a fost editat i compilat, utilizatorul poate introduce n fereastra de dialog diverse formule de interogare a sistemului. O formul de interogare, denumit goal n terminologia englez, este de forma: (n1) p1,p2, , pn. unde p1,p2,,pn sunt termeni executabili, iar virgula are semnificaia de conjuncie logic. O formul de interogare poate fi de dou feluri: determinit: nu conine variabile libere, rspunsul sistemului la o astfel de formul fiind yes sau no, dup cum formula respectiv este sau nu o consecin logic a clauzelor din program; nedeterminist: conine una sau mai multe variabile libere, sistemul determinnd prin backtracking toate instanierile posibile ale variabilelor pentru care respectiva formul este o consecin logic a clauzelor din program. Exemplu: place (ion, X) :- are_zestre(X), frumoas (X). are_zestre(X) :- bogat(Y), fata (X, Y). ... ?: place (ion, Fata). %(i, o)
IASE
9/19
Remarca 1: De fiecare dat cnd are de satisfcut un goal introdus n fereastra de interogare sau din corpul unei reguli, interpretorul Prolog ncepe scanarea tuturor clauzelor din program ncepnd cu prima dintre acestea, n vederea gsirii unei clauze al crei antet este unifiabil cu goal-ul curent. {place(ion, X), place(ion, Fata)} cmgu {Fata=X}. Remarca 2: Dac un goal a fost unificat cu antetul unei reguli, se trece la demonstrarea predicatelor (subgoal-urilor) din corpul regulii respective. ncercarea de a satisface aceste fapte se face n ordinea n care acestea apar n corpul regulii. Astfel, se trece la a demonstra bogata (Y) devine goal curent. Remarca 3: Dac un predicat din corpul unei reguli a fost demonstrat, se trece la demonstrarea predicatului urmtor; n caz contrar, se revine la ultimul punct de breakpoint aflat n program. Goal-ul curent devine fata(X, veta). Cnd mai multe clauze din program sunt unifiabile cu goal-ul curent, interpretorul plaseaz un punct de breakpoint pe urmtoarea clauz unifiabil din program. fata(X, veta) fata(geta, veta), C = {X=geta} = C = {Fata=X=geta, Y=veta} frumoasa(geta). Remarca 4: Cnd un goal este dovedit inconsistent, se revine prin backtracking la ultimul punct de breakpoint plasat n program. O dat cu revenirea la ultimul punct de breakpoint, se elibereaz toate variabilele instaniate dup plasarea n program a respectivului punct de breakpoint. Variabila X este eliberat (dezlegat de valoarea geta). Revenindu-se la punctul de breakpoint, variabila X este instaniat din nou cu valoarea maria. n acest caz, goal-ul frumoasa (maria) poate fi demonstrat i Prolog, innd cont de substituia curent, rspunde Fata=maria. Urmtoarele 2 caracteristici exprim o particularitate relevat a limbajului Prolog: Singura modalitate de instaniere a unei variabile este procedura de unificare (programatorul nu poate atribui o valoare unei anumite variabile). Variabilele pot fi eliberate numai prin mecanismul de backtracking al interpretorului Prolog. n Prolog, simbolul = este un operator infix care face apel la procedura de unificare; n urma unificrii variabilelor din cei doi termeni, instanierea se realizeaz dac X este liber. X=1+2 are drept efect instanierea lui X cu expresia 1+2 dac X este liber: ={X=1+2}. X=1 are ca efect instanierea variabilei X = 1, dac X este liber. ={X=1}. X=1, X=X+1: ={X=1} 1=1+1 inconsistent => fail, , (1)=(1+1). Exemple BAF i CAF: prezent(alina). prezent(georgiana). prezent(elena). prezent(mircea). prezent(dan). lista:prezent(X), write(X), nl, fail. lista. % BAF(Backtracking After Fail) lista:prezent(X), write(X), nl, X=dan, !. % CAF(Backtracking After Fail) Precizare: O formul de interogare Q trebuie privit ca un apel la mecanismul inferenial al interpretorului (demonstratorul) Prolog, care genereaz soluiile lui Q.
IASE
10/19
3. Concatenarea a dou liste concat([], L, L). concat([H|T], L2, [H|T2]):- concat(T, L2, T2). 4. tergerea uni element al unei liste del(X, L, L1). Prin teregerea unui element X din lista L se obine lista L1. L1 L L1 L2 concat(L1, L2, L) L2
IASE
11/19 del(X, [X|T], T). del(X, [H|T], [H|T1]):- del(X, T, T1). ? del(b, [a,b,c,b,d],L).
L=[a,c,b,d] L=[a,b,c,d] 5. Inserarea unui element ntr-o list insert(X, L, L1):- del(X, L1, L). 6. Permutarea elementelor unei liste perm (L, L1) perm([], []). perm([H|T], L):- perm(T, T1), insert(H, T1, L). 7. Numrarea elementelor unei liste count(L, N) count([], 0). count([H|T], N):- count(T,M), N is M+1. sau count([], N, N). count([_|T], Numar, N):- NouNumar is Numar+1, count(T,NouNUmar, N). Numar se va initializa cu zero. ?: count([1,2,3,4,5], 0, Cate). Cate=5 count(L, N):-count(L,0,N). ?: count([1,2,3,4,5], Cate). Cate=5.
2.6. Operatori
Dat fiind faptul c limbajul Prolog este orientat mai degrab n vederea efecturii calculelor simbolice dect numerice, operatorii trebuie privii ca un mod aparte de reprezentare a termenilor compui de aritate unu sau doi. Deci un operator nu semnific de regul efectuarea unei operaii, ci indic mai degrab modul de agregare a operanzilor n cadrul structurii desemnat de acel operator. Exist totui i o serie de operatori prin care programatorul poate fora la nevoie evaluarea unei expresii. Spre deosebire de sintaxa standard a unui termen compus, situaie n care functorul precede paranteza ce conine lista argumentelor sale, operatorii permit scrierea termenilor de aritate 1 sau 2 ntr-o nou sintax, care ntr-un anumit context poate fi mult mai agreabil. Pentru a prezenta aceast sintax, previzibil de fapt, trebuie menionat mai nti c operatorii pot fi de trei feluri i anume operatori prefix, postfix i infix. Pentru desemnarea unui operator se poate utiliza un atom de oricare din cele trei tipuri prezentate mai sus. Operatori prefix. Un operator prefix este un operator unar care se scrie n faa (precede) operandului acestuia (de exemplu, semnul minus din faa unui numr negativ este un operator prefix). Operatorii prefix pot fi utilizai pentru exprimarea unor termeni de aritate unu. De exemplu, termenul Prolog functor(termen) poate fi exprimat la fel de bine i n scrierea functor termen dac functor este sau a fost declarat (modul de declarare va fi prezentat ulterior) un operator prefix. Predicatul predefinit not/1 este un exemplu de operator prefix. Predicatul not este adevrat dac argumentul su este fals i fals dac argumentul este adevrat. Astfel, termenul not dangerous(Animal) din exemplul de mai jos nu este altceva dect exprimarea prefix a termenului not(dangerous(Animal)). Operatori postfix. Un operator postfix este un operator unar care succede operandul acestuia. Ca i n cazul operatorilor prefix, operatorii postfix pot fi utilizai pentru expri-marea, ntr-un mod diferit de sintaxa standard Prolog, a termenilor de aritate unu. De exemplu, termenul functor(termen) poate fi exprimat la fel de bine i n scrierea
IASE
12/19
termen functor dac functor este sau a fost declarat operator postfix. Operatori infix. Un operator infix este un operator binar care se scrie ntre operanzii acestuia (scrierea algebric uzual). Ca i n cazul operatorilor unari, operatorii infix permit scrierea termenilor de aritate 2 i ntr-o sintax diferit de cea standard Prolog. De exemplu, termenul functor(termen1,termen2) se poate scrie sub forma termen1 functor termen2 dac functor este sau a fost declarat operator infix. Dac functorul is_a este declarat operator infix, atunci clauzele corespunztoare acestui predicat pot fi scrise n maniera prezentat mai jos: mowgli is_a man. rama is_a wolf. bagheera is_a panther. baloo is_a bear. thati is_a elephant. kaa is_a snake. shere_khan is_a tiger. n aceast situaie, o ntrebare de tipul Cine este o panter ? se poate formula sub forma: ?- Who is_a panther. Precedena operatorilor. tiind c + i * sunt doi operatori infix predefinii n limbajul Prolog, se pune ntrebarea care dintre urmtorii doi termeni, +(a,*(b,c)) respectiv *(+(a,b),c) , este interpretarea corect a expresiei (termenului) a+b*c? Sau, algebric vorbind, termenul respectiv este evaluat ca a+(b*c) sau (a+b)*c? nainte de a se da un rspuns la aceast ntrebare, trebuie precizat faptul c n Prolog fiecare operator are sau i se asociaz o preceden, constnd ntr-un numr natural cuprins ntre 1 i 1200. Cu ct precedena unui operator este mai mic cu att operatorul este mai avid la operanzi sau, cum se zice n terminologia programrii logice, leag mai bine. Acest principiu se poate formula, mai simplu, dup cum urmeaz: functorul principal al unui termen compus format din operatori de precedene diferite este operatorul cu precedena cea mai mare. Precedena implicit (aceasta putnd fi modificat de programator prin redefinirea operatorilor) a operatorilor + i * este 500 respectiv 400. Prin urmare, expresia considerat este exprimarea algebric a termenului compus +(a,*(b,c)), dat fiind faptul c atomul b este operandul lui * care leag mai bine dect + sau, altfel spus, dat fiind faptul c functorul principal este operatorul +, deoarece acesta are precedena mai mare dect *. Trebuie subliniat faptul c n Prolog operatorii nu implic existena unor date asociate sau efectuarea unor calcule, dect n situaii cu totul speciale. Operatorii au rol de functor i specific un mod de structurare. Limbajul Prolog accept totui scrierea n format algebric a termenilor avnd drept functori operatori unari sau binari, dar aceste expresii sunt doar un mod extern de reprezentare a termenilor respectivi. Intern, orice expresie este un termen i se reprezint ca i oricare alt termen compus (arbore). Se pune acum ntrebarea cum trebuie interpretat o expresie n care intervin mai muli operatori de aceeai preceden, de exemplu o expresie de forma: t1 t 2 t n unde t1,t2,,tn sunt termeni, iar prin s-a notat un operator oarecare, sau diveri operatori avnd aceiai preceden. n ce condiii o astfel de expresie este sintactic corect (reprezint un termen) i cum trebuie interpretat aceasta? Rspunsul la aceast ntrebare necesit asimilarea n prealabil a noiunii de tip al unui operator. nelegerea acestui concept permite interpretarea corect a oricrei termen Prolog, indiferent de complexitatea acestuia. Tipul operatorilor. Pe lng precedena acestuia, un operator este caracterizat prin tip, adic un descriptor care caracterizeaz proprietile operatorului respectiv. Descriptorii utilizai pentru definirea operatorilor sunt cei prezentai mai jos: Operatori prefix: fx fy Operatori postfix: xf yf Operatori infix: xfx xfy yfx Semnificaia descriptorilor este urmtoarea: Litera f (f provine de la functor) desemneaz locul de plasare al operatorului n raport cu operandul sau operanzii acestuia, desemnat sau desemnai prin simbolul x i/sau y. Pentru a nelege care este
IASE
13/19
deosebirea dintre x i y trebuie ca n prealabil s se defineasc noiunea de preceden a unui termen. Un termen simplu sau inclus ntre paranteze este de preceden 0: Precedena unui termen compus este egal cu cea a functorului su principal. Litera x din descriptorii de mai sus arat c precedena termenului asociat trebuie s fie strict mai mic dect precedena operatorului; Litera y specific c aceasta trebuie s fie cel mult egal cu cea a operatorului. De exemplu, dac operatorul i se atribuie ca tip descriptorul yfx atunci expresia t1 t 2 t 3 este corect i trebuie interpretat ca (t1 t 2 ) t 3 , fapt pentru care un operator yfx mai este denumit asociativ la stnga. Se poate constata c interpretarea t1 (t 2 t 3 ) nu este posibil deoarece precedena termenului (t 2 t 3 ) corespunztoare descriptorului x ar fi egal cu cea a operatorului . Dac ns tipul operatorului ar fi xfy atunci cea de a doua interpretare ar fi corect i operatorul ar fi asociativ la dreapta. n sfrit, dac descriptorul de tip al operatorului este xfx, atunci expresia t1 t 2 t 3 este incorect i operatorul este denumit neasociativ. Recapitulnd, descriptorii de tip utilizai la definirea operatorilor sunt cei enumerai mai jos, n dreapta acestora fiind specificat() tipul (proprietatea) operaiei respective: fx operator prefix neasociativ; fy operator prefix asociativ la dreapta; xf operator postfix neasociativ; yf operator postfix asociativ la stnga; xfx operator infix neasociativ; xfy operator infix asociativ la dreapta; yfx operator infix asociativ la stnga. Declararea operatorilor. Pe lng operatorii uzuali predefinii n limbajul Prolog, programatorul poate s i defineasc propriii lui operatori. Declararea unui operator se realizeaz prin intermediul comenzii op al crei format este: :- op(<precedena>,<descriptor tip>,<nume>). De exemplu, prin comanda :- op(500,xfx,is_a). este definit operatorul infix neasociativ is_a utilizat n exemplul precedent. Definiiile implicite ale principalilor operatori uzuali sunt prezentate mai jos: :- op(1200, xfx, :-). :- op(1200, fx, [ :-, ?-]). :- op(1100, xfy, ;). :- op(1000, xfy, ,). :- op(700, xfx, [=, is , < , > , = < , > = , = = , \ = = , = : = , = \ = ] ). :- op(500, yfx, [ +, - ]). :- op(500, fx, [ + , - , not]). :- op(400, yfx, [ * , \ , div]). :- op(300, xfx, mod). Noiunea de preceden a unui termen se definete astfel: un termen atomic sau inclus ntre paranteze are precedena zero; precedena unui termen compus este cea a functorului su. Oricare din operatorii de mai sus pot fi la nevoie redefinii de programator. Definiia curent a unui operator poate fi consultat prin apelarea predicatului current_op/3, al crui prototip este current_op(<Preceden>,<Tip>,<Nume>). Astfel prin apelul: current_op(P, T, +) , variabilele libere P i T vor fi instaniate cu precedena respectiv tipul operatorului + (se obin prin backtracking ambele soluii, att pentru operatorul unar ct i pentru cel binar).
IASE
14/19
Remarca 4. Din punct de vedere pur sintactic, o regul poate fi considerat de asemenea un termen compus al crui functor principal este operatorul infix neasociativ :-, virgula de separare a termenilor executabili din partea dreapt a acestui operator fiind considerat un operator prefix asociativ la dreapta (vezi definiiile operatorilor respectivi n tabelul de mai sus). Operaii cu termeni. Orice operator care constituie functorul principal al unui termen compus are o semnificaie predicativ i are n consecin o valoare de adevr. n funcie de rolul i semnificaia acestora, operatorii utilizabili la formarea expresiilor Prolog se pot mpri n urmtoarele patru categorii precizate mai jos. Operatorul de unificare. Cea mai important operaie pe mulimea termenilor este unificarea (de fapt aceasta este operaia de baz a limbajului Prolog). Se tie c doi termeni t1 i t2 se numesc unifiabili dac exist o substituie astfel nct termenii (t1) i (t2)s devin identici. Operaia de unificare este desemnat prin operatorul infix =. Termenul executabil t1=t2 este de fapt un apel la rutina de unificare a interpretorului Prolog. Dac cei doi termeni sunt unifiabili, atunci predicatul t1=t2 este satisfcut i variabilele libere din cei doi termeni sunt substituite prin valorile lor corespunztoare din cmgu(t1,t2). n caz contrar, termenul t1=t2 este inconsistent, iar variabilele din componena acestora rmn nemodificate. Se poate testa dac doi termeni t1=t2 sunt unifiabili i fr a produce instanieri ale variabilelor prin apelarea predicatului predefinit unifiable(t1,t2). Operatorul \= este complementul operatorului =. Astfel t1\=t2 este adevrat dac t1 i t2 sunt neunifiabili i este fals cnd t1 i t2 sunt unifiabili. Operatori de comparaie lexicografic. Operatorul == (dou semne de egalitate) permite compararea lexicografic a doi termeni. Termenul (predicatul) t1==t2 este valid dac cei doi termeni t1 i t2 sunt lexicografic identici. De exemplu, termenul a+b==b+a este inconsistent, deoarece termenii a+b i b+a nu sunt identici, n schimb predicatul a+b==a+b este valid. Operatorul \== (back slash i dou semne de egalitate) este negaia operatorului precedent. Astfel, predicatul a+b\==b+a este adevrat, n timp ce predicatul a+b\==a+b este fals. Operatorii din aceast categorie nu produc instanieri ale variabilelor. Operatorul de evaluare. Dup cum s-a precizat mai sus, limbajul Prolog este orientat pentru efectuarea calculului simbolic, operatorii fiind utilizai mai degrab pentru reprezentarea unor structuri. Evident, sfera de utilizare a limbajului ar fi puternic diminuat, dac acesta nu ar permitea efectuarea unor calcule matematice. Dar, aceste calcule se fac numai la cererea expres a programatorului. De exemplu, dac X este o variabil liber, termenul executabil X = 1+2 are ca efect instanierea variabilei X cu valoarea (termenul) 1+2 (ceea ce era de ateptat ntruct 1+2 este substituia de unificare a celor doi termeni ai operatorului =). Operatorul prin care programatorul poate cere n mod expres evaluarea unei expresii este desemnat prin atomul rezervat is. n partea stng a operatorului is trebuie s apar n mod obligatoriu o variabil (liber sau nu), iar n partea dreapta o expresie algebric, ale crei variabile (dac exist) s fie iniializate cu valori numerice. Astfel, dac X este o variabil liber, apelul termenului X=1+2 va avea ca efect instanierea variabilei X cu valoarea 3. Trebuie menionat faptul c un termen executabil de forma: X is <Expresie> , nu trebuie confundat cu o instruciune de atribuire. De fapt, dei pare oarecum ocant, limbajul Prolog nu are instruciune de atribuire !. Mai mult, un predicat de forma: X is X+1 , este inconsistent, deoarece variabila X din membrul drept trebuie s fie instaniat i, indiferent de valoarea acesteia, aceasta nu poate fi nici cum egal cu X+1. Dup cum s-a menionat anterior, n Prolog unificarea este singurul mod de instaniere a unei variabile, dup cum mecanismul de backtracking este singurul mod posibil de eliberare al acesteia. Operatori relaionali. Limbajul Prolog conine urmtorii operatorii relaionali, ce pot fi utilizai pentru comparaia numeric a dou expresii. Toate variabilele cuprinse n cele dou expresii trebuie s fie instaniate n momentul apelului termenului respectiv. E1=:=E2 egalitate E1=\=E2 neegalitate E1<E2 mai mic
IASE
15/19
E1=<E2 mai mic sau egal E1>E2 mai mare E1>=E2 mai mare sau egal Fiecare din termenii de mai sus produce evaluarea numeric a expresiilor algebrice E1 i E2, valoarea de adevr a termenilor de mai sus fiind calculat ca n orice alt limbaj de programare. Operatorii relaionali nu produc instanieri ale variabilelor din cele dou expresii. Observaie. Operatorii mai mic sau egal i mai mare sau egal trebuie scrii n maniera ilustrat mai sus, scrierile <= respectiv => nefiind acceptate de compilatorul Prolog.
IASE
p(a1)
p(a2)
p(an)
Da
C(X)
fail
Nu fail
Exemplu: introducere :repeat, write(Continuati:), read(Continuat), nl, write(Tara:), read(Tara), nl, write(Capitala:), read(Capitala), nl, memorare(Continent, Tara, Capitala), Tara=stop,!. Predicatul repeat/1 salut:- (repeat(6), write(Salut!), nl, fail); true. repeta(0):-!. repeta(N):- M is N-1, repeta(M). integer_bound/3 {(i,o,i)} integer_bound(vmin, V, vmax). for:- (integer_bound(1, I, 10), Ip is I*I, write(I), write(Ip), nl, Ip=10, fail); true. Predicatele findall/3, bagof/3, setof/3 Predicatul findall are urmtoarea sintax: findall(Termen, Obiectiv, Lista). Obiectivul este precizat sub forma: 1 Obiectiv, 2 Obiectiv, ..., n Obiectiv. Lista predicatul findall produce lista cu valoarea 1 Termen, 2 Termen, ..., n Termen. findall(C, stat(europa, _, C), LCE). LCE=[bucuresti, tirana] findall(C, stat(_, _, C), LCE). findall(oras(C), stat(europa, _, C), LoE). LoE=[oras(bucuresti), oras(tirana)] Predicatul bagof are urmtoarea sintax: bagof (Termen, V1 V2.. VnObiectiv(V1,V2,.., Vn), Lista). n care Vi sunt variabile cuantificate existenial. Variabilele care apar n obiectiv i care nu sunt
IASE
17/19
specificate ca existenial cuantificate i nu apar nici n Termen, sunt considerate variabile libere. Predicatul bagof genereaz prin backtraking argumentul Lista pentru toate instanierile posibile ale variabilelor. bagof(Cap, Tarastat(Cont, Tara, Cap), L). ? Cont=europa L=[bucuresti, tirana] ? Cont=africa L=[rabat, cairo] ? Cont=asia L=[bangkok] bagof(Cap, ContTarastat(Cont, Tara, Cap), L). L=[bucuresti, tirana, rabat, cairo, bangkok] Predicatul setof(Termen, V1 V2.. VnObiectiv(V1,V2,.., Vn),, Lista) genereaz toate insanele Termen pentru care un goal Prolog este true. elimin soluiile duplicat i ordoneaz elementele listei (n conformitate cu ordonarea utilizat de predicatul compare/3). Exemplul 1. Se consider programul Prolog constituit din urmtoarea succesiune de fapte: is_a(mowgli, man). is_a(rama, wolf). is_a(bagheera, panther). is_a(baloo, bear). is_a(thati, elephant). is_a(kaa, snake). is_a(shere_khan, tiger). man_eating(tiger). dangerous(snake).
i se atribuie acestor fapte interpretarea care ne situeaz n universul mirific imaginat de Rudyard Kipling n Cartea junglei. Aceste fapte definesc relaia is_a/2 prin enumerarea elementelor sale. Interpretarea acestor fapte n limbajul natural, n contextul amintit mai sus, este urmtoarea: Mowgli is a man, Bagheera is a panther, Baloo is a bear .a.m.d. Faptele de mai sus se pot rescrie ntr-o form similar utiliznd atomii de tip quote. De exemplu, dac se dorete ca numele celebrului tigru, i nu numai, s se scrie n ortografia sa natural, ultima din instanele predicatului is_a/2 s-ar putea scrie sub forma: is_a(Shere Khan, tiger). Se presupune n continuare c se dorete definirea unei relaii friend/1 care s stipuleze care din personajele de mai sus sunt prietenii lui Mowgli. Pentru aceasta se poate aduga programului de mai sus cte o instan a predicatului friend/1 corespunztoare fiecruia din personajele de mai sus, mai puin tigrul Shere Khan i pitonul Kaa: friend(bagheera). friend(baloo). friend(rama). friend(thati). Relaia friend/1 se poate defini ns i observnd c Mowgli este prietenul fiecruia din personajele de mai sus, mai puin cei doi dumani declarai ai acestuia, tigrul mnctor de oameni Shere Khan i periculosul piton Kaa. friend(Name):is_a(Name,Animal), not man_eating(Animal), not dangerous(Animal). Analog, se poate defini o regul enemy/1 prin care pot deduce dumanii lui Mowgli: enemy (Name) :is_a(Name,Animal), (man_eating(Animal) ; dangerous(Animal)). n contextul de mai sus, simbolul ; (punct i virgul) are semnificaia de disjuncie logic.
IASE
18/19
De exemplu, n cazul exemplului considerat mai sus, sistemul va rspunde la ntrebrile formulate (textul introdus de operator apare subliniat) n maniera prezentat mai jos. ?:- is_a(baloo,bear). Este Baloo un urs? yes ?:- is_a(bagheera,bear). Este Bagheera un urs? no ?:- is_a(thati,What). Ce este Thati? What=elephant. yes. Semnificaia acestor ntrebri este cea nscris n partea dreapt. La ntrebarea: ?:- is_a(Who,What). Cine este ce? sistemul va rspunde indicnd toate instanierile posibile ale variabilelor Who i What pentru care formula precedent este deductibil din program, obinndu-se astfel ntreaga distribuie a personajelor. Who=mowgli, What=man Who=rama, What=wolf Who=bagheera, What=panther Who=baloo, What=bear Who=thati, What=elephant Who=kaa, What=snake Who=shere_khan, What=tiger Observaie. La formulele de interogare nedeterministe, dup afiarea unei soluii sistemul ateapt ca operatorul s apese una din urmtoarele taste: <spaiu> <CR> pentru continuarea afirii celorlalte soluii posibile; dac se renun la restul soluiilor.
Exerciiul 1. Editai programul Prolog prezentat mai sus i scriei formula de interogare prin care se pot afia toi prietenii lui Mowgli. Remarca 1. Interpretorul Prolog rspunde la formulele de interogare ale utilizato-rului numai pe baza clauzelor (fapte i/sau reguli) din program. De exemplu, la ntrebarea: ?:- is_a(thati, colonel). sistemul va rspunde cu no, dei n povestea considerat Thati este ntr-adevr colonel, (re)cunoscut de ntreaga jungl prin rsuntoarele maruri ale patrulei sale. Revenind la programul prezentat mai sus, dac functorul is_a este declarat operator infix, atunci clauzele corespunztoare acestui predicat pot fi scrise n maniera prezentat mai jos: mowgli is_a man. rama is_a wolf. bagheera is_a panther. baloo is_a bear. thati is_a elephant. kaa is_a snake. shere_khan is_a tiger. n aceast situaie, o ntrebare de tipul Cine este o panter ? se poate formula sub forma: ?- Who is_a panther. Exerciiul 2. ncercai s anticipai ce va rspunde interpretorul Prolog la ntrebarea Who is_a Panther. . Este corect formula de interogare Bagheera is_a bear. i, dac da, cum va rspunde
IASE
19/19
interpretorul Prolog n acest caz ?. Ce este de fapt Bagheera i care este ntrebarea prin care se poate afla acest lucru ? De exemplu, prin comanda :- op(500,xfx,is_a). este definit operatorul infix neasociativ is_a utilizat n exemplul precedent. Remarca 3. Este bine ca definirea operatorilor s se fac pornind de la structura arborescent a termenilor pe care acetia i reprezint. De exemplu, structura termenului desemnat prin ultima clauz a programului de mai jos este cea ilustrat n figura alturat. is a :- op(800,xfx,is_a). :- op(500,fy,[black, big,man, eating]). man bagheera is_a black panther. baloo is_a big bear. shere_khan eating shere_khan is_a man eating tiger. Dup cum se poate constata mai muli operatori de tiger acelai tip i avnd aceiai preceden pot fi declarai n bloc, indicnd lista operatorilor respectivi ca cel de al treilea parametru al comenzii op. Din analiza arborelui de mai sus se poate constata c operatorii is_a, man i eating sunt corect definii. Operatorul is_a este infix, nodul corespunztor avnd doi descendeni, termenii respectivi avnd precedene (shere_khan=0, man=500)) strict mai mici dect cea a operatorului. Operatorii man este un operator prefix de tipul fy i se aplic termenului eating tiger, a crui preceden, egal cu cea a functorului eating, este egal cu cea a operatorului. n sfrit, operatorul prefix eating se aplic termenului tiger de preceden egal cu 0. De remarcat c dintre cei doi operatori prefix de mai sus, numai eating ar putea fi definit cu descriptorul fx. Altfel spus, operatorii prefix care nu au ca descendent o frunz (un termen simplu) trebuie s fie n mod obligatoriu de tip fy (sunt neasociativi). Exerciiul 3. Reprezentai termenul de mai jos: noaptea toate pisicile sunt negre , sub form arborescent i definii n mod corespunztor operatorii afereni, astfel nct enunul respectiv s fie un termen Prolog valid. Definii o colecie de predicate care s permit scrierea unor enunuri similare, avnd structura: [<complement circumstanial de timp>] [<atribut adjectival>] <subiect> <predicat nominal>.