Sunteți pe pagina 1din 183

Programare Logic

Nicolae Constantinescu

Cuprins
Prefa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 0.1 Introducere. Fapte. Reguli . . . . . . . . . . . . . . . . . . . . . 15 0.1.1 0.1.2 0.1.3 0.1.4 0.2 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 15 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 28 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 28

Termeni. Variabile. Backtracking. Predicatele-sistem trace, read, write . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 0.2.1 0.2.2 0.2.3 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 29 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 40 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 40

0.3

Unicarea. Operaiile aritmetice . . . . . . . . . . . . . . . . . . 41 0.3.1 0.3.2 0.3.3 0.3.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 41 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 48 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 48 3

0.4

Recursivitate. Predicatele !(cut) i fail . . . . . . . . . . . . . . 49 0.4.1 0.4.2 0.4.3 0.4.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 49 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 64 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 64

0.5

Turnurile din Hanoi. Funciile Fibonacci i Ackermann . . . . . 65 0.5.1 0.5.2 0.5.3 0.5.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 65 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 71 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 72

0.6

Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 0.6.1 0.6.2 0.6.3 0.6.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 73 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 98 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 99

0.7

Grafuri. Arbori . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 0.7.1 0.7.2 0.7.3 0.7.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 100 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 105 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 105

0.8

Probleme speciale . . . . . . . . . . . . . . . . . . . . . . . . . . 106 0.8.1 0.8.2 Problema Damelor . . . . . . . . . . . . . . . . . . . . . 106 Problema mutrii calului . . . . . . . . . . . . . . . . . . 108 4

0.8.3 0.8.4 0.9

Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 110 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 110

Fiiere. Baze de date dinamice . . . . . . . . . . . . . . . . . . . 112 0.9.1 0.9.2 0.9.3 0.9.4 Fundamente teoretice . . . . . . . . . . . . . . . . . . . . 112 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Exerciii propuse . . . . . . . . . . . . . . . . . . . . . . 120 Teme de studiu . . . . . . . . . . . . . . . . . . . . . . . 121 123

1 Probleme de la concursurile de programare 1.1

Probleme de la concursurile de programare . . . . . . . . . . . . 124 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 Ascii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Staii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Triplete . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Spirala . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Perioada . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 Numere . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Triunghi . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 Diamant . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 Drum . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

1.1.10 Tabla

1.1.11 arpele belgian . . . . . . . . . . . . . . . . . . . . . . . 135 1.1.12 Hexagon . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 2 Soluiile problemelor propuse 5 139

2.1

Introducere. Fapte. Reguli . . . . . . . . . . . . . . . . . . . . . 139 2.1.1 2.1.2 2.1.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 139 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 142

2.2

Termeni. Variabile. Backtracking. Predicatele-sistem trace, read, write . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 2.2.1 2.2.2 2.2.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 145 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 146

2.3

Unicarea. Operaiile aritmetice . . . . . . . . . . . . . . . . . . 149 2.3.1 2.3.2 2.3.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 150 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 150

2.4

Recursivitate. Predicatele !(cut) i fail . . . . . . . . . . . . . . 151 2.4.1 2.4.2 2.4.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 151 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 152

2.5

Turnurile din Hanoi. Funciile Fibonacci i Ackermann . . . . . 152 2.5.1 2.5.2 2.5.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 152 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Cod Surs . . . . . . . . . . . . . . . . . . . . . . . . . . 153

2.6

Liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 2.6.1 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 153 6

2.6.2 2.6.3 2.7

Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 155

Probleme speciale . . . . . . . . . . . . . . . . . . . . . . . . . . 156 2.7.1 2.7.2 2.7.3 Soluie teoretic . . . . . . . . . . . . . . . . . . . . . . . 156 Apel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Cod surs . . . . . . . . . . . . . . . . . . . . . . . . . . 157

2.8

Fiiere. Baze de date dinamice . . . . . . . . . . . . . . . . . . . 158 2.8.1 2.8.2 Soluia problemei 0.9.1 . . . . . . . . . . . . . . . . . . . 159 Soluia problemei 0.9.2 . . . . . . . . . . . . . . . . . . . 163 167

3 Anexa Predicate 3.1

Anexa predicate . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 Notaiile predicatelor . . . . . . . . . . . . . . . . . . . . 168 ncrcarea ierelor surs . . . . . . . . . . . . . . . . . . 168 Compararea i unicarea termenilor . . . . . . . . . . . . 168 Predicate de control . . . . . . . . . . . . . . . . . . . . 169 Baze de date dinamice . . . . . . . . . . . . . . . . . . . 170 Intrri i Ieiri . . . . . . . . . . . . . . . . . . . . . . . . 170 Predicate primitive pentru I/O . . . . . . . . . . . . . . 173 Citirea i scrierea termenilor . . . . . . . . . . . . . . . . 174 Predicate pentru operaii cu liste . . . . . . . . . . . . . 175

3.1.10 Predicate aritmetice . . . . . . . . . . . . . . . . . . . . 176 3.1.11 Funcii aritmetice . . . . . . . . . . . . . . . . . . . . . . 177 3.1.12 Urmrirea execuiei programului . . . . . . . . . . . . . . 179 7

List de guri
1 1.1 1.2 1.3 1.4 1.5 1.6 Fereastra pentru trace n mod grac . . . . . . . . . . . . . . . . 35 Exemple de apel pentru N=5 i respectiv N=3 . . . . . . . . . . 124 Exemplu de display digital . . . . . . . . . . . . . . . . . . . . . 129 Tabla nemodicat de spiritul ru . . . . . . . . . . . . . . . . . 132 Tabla alterat . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Exemplu de tabl i reprezentarea corespunztoare . . . . . . . 134 Hexagon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

10

List de tabele
1 2 3 4 5 Funcii trigonometrice disponibile n SWI-Prolog . . . . . . . . . 43 Funcii matematice disponibile n SWI-Prolog . . . . . . . . . . 44 Predicatele aritmetice in SWI-Prolog . . . . . . . . . . . . . . . 45 Cteva valori ale funciei Ackermann . . . . . . . . . . . . . . . 70 Valorile funciei Ackerman calculate n SWI-Prolog . . . . . . . 71

11

Prefa
Programarea logic este o paradigm a programrii declarative, bazat pe logica de ordinul I. Teza potrivit creia logica de ordinul I este un util i practic limbaj de programare non-deterministic de nivel nalt cu un solid fundament teoretic aparine lui R. Kowalsky, care dezvolt un punct de vedere relaional al calculabilitii ca deducie, sintetizat prin urmtoarea formul: Calculabilitate = Logic + Control Dac punem n antitez relaia lui Kowalsky cu cea a lui N. Wirth potrivit creia: Program = Structuri de date + Algoritm observm c, n domeniul programrii procedurale - trebuie rezolvate la nivelul codului att aspectele logice, ct i cele de control declarative - trebuie rezolvate numai cele de control. Considernd c un program logic este constituit dintr-o familie de axiome i o int, iar regulile de inferen determin faptul c axiomele sunt suciente pentru a proba veridicitatea intei, execuia unui program logic corespunde construciei unei demonstraii a intei pe baza axiomelor ataate programului. Practic, execuia unei secvene de cod n programarea logic este realizat prin intermediul unui demonstrator rezolutiv de teoreme. Plecnd de la aceste 12

observaii i analiznd relaia dintre calculabilitate i deducie, aa cum a fost ea tratat de P. J. Hayes1 , putem concluziona c un interpretor al unui limbaj de programare i un demonstrator automat de teoreme (motor de inferene) au structuri practic identice, iar avantajele de natur practic i teoretic sunt obinute prin combinarea celor dou metodologii. n fapt, Kowalsky i Hayes propun un comportament convergent pentru deducie i calculabilitate. Teza este similar celei potrivit creia sistemele de gestiune a bazelor de date pot vzute drept colecii de structuri relaionale care denesc logica datelor. Colmerauer implementeaz ideea n construcia limbajului de programare PROLOG (PROgramming in LOGic), bazndu-se i pe o important lucrare a lui A. Robinson2 i utiliznd de la Kowalsky conceptul de "clauz Horn", fundamentnd astfel strategia bazat pe o demonstraie linear cu backtracking i unicarea capetelor de clauze. Limbajul PROLOG al acestui nceput nu era la fel de matur ca limbajul LISP, dar implementarea realizat de H.D. Warren a condus la mbuntiri substaniale ale limbajului. Compilatorul a fost scris aproape integral n PROLOG, translatnd clauzele PROLOG n instruciuni ale unei maini abstracte cunoscut sub numele de Maina Abstract Warren (WAM).

P. Hayes, Computation and deduction, Proc. 2nd Symp. on Mathematical Foundations

of Computer Science (MFCS), Czechoslovakian Academy of Sciences, Prague, 1973, pp. 105-118. 2 Robinson J.A., A machine-oriented logic based on the resoulution principle, J. ACM 12,1, pp. 23-41, January 1965.

13

Clocksin i Mellish continu efortul de perfecionare a limbajului obinnd o versine acceptat ca standard si numit "sintax C&M" sau "sintax Edinburgh". Dintre dialectele limbajului PROLOG amintim Quintus PROLOG, C-PROLOG, Turbo PROLOG, Visual PROLOG, SWI-PROLOG, PROLOG, B-PROLOG, BinProlog, GNU Prolog, jPROLOG, SICStus PROLOG , Amzi PROLOG etc. Cu toate aceste importante realizri, comunitatea specialitilor n informatic, n general i cea a specialitilor n inteligen articial, n particular, nu au acordat atenia cuvenit programrii logice. O schimbare de atitudine s-a nregistrat odat cu lansarea "Japanese Fifth Generation Project", care a redenit importana programrii logice pentru urmtoarele generaii de calculatoare. Din acel moment limbajul PROLOG a cunoscut o dezvoltare permanent. O paradigm mai recent este cea a Constraint Language Programming (CLP), unde domeniul nu este restricionat la universul Herbrand i unde unicarea este nlocuit cu satisfacerea restriciilor. O instan a acestei abordri poate considerat CLP(R) (Constraint Logic Programming over the Real domain), cu implementarea operatorilor aritmetici (+,-,*,/) i a funciilor sin, cos etc.

14

0.1
0.1.1

Introducere. Fapte. Reguli


Fundamente teoretice

PROLOGul a fost inventat la nceputul anilor 70 de ctre Alain Colmerauer n Frana (PROgramming in LOGic=PROLOG). Printre aplicaiile la care poate folosit PROLOG-ul se numr: sisteme expert, limbaje de specicaie, nelegerea limbajelor naturale, baze de date, programarea roboilor i automatizarea gndirii articiale. Un program este, n general, compus din dou elemente din care unul este predominant, ne referim la noiunile de logic i control. Acestea sunt elementele care descriu ce face un program i respectiv cum procedeaz pentru a ajunge la o soluie (spre exemplu n programarea structurat prin intermediul unui algoritm se ajunge la o soluie, iar secvena de instruciuni ale algoritmului este ce se ntmpl pentru a se ajunge la soluie ). Limbajele care aparin programrii structurate descriu pas cu pas modul n care programul trebuie s se comporte pentru ca dup un numr nit de pai s se obin soluia, de aceea spunem c programarea structurat urmeaz paradigma imperativ. Aceste limbaje nu sunt ns lipsite de componenta descriptiv, dincolo de modul imperativ. S spunem c avem nevoie la un moment dat s calculm o valoare, printr-o instruciune vom descrie i modul n care valoarea va obinut. Prin contrast, programarea logic se bazeaz pe alegerea predicatelor care descriu cel mai bine relaiile care exist ntre obiecte, indc ele vor cele care vor 15

stabili legtura ntre datele de intrare i cele de ieire. Dac aceast legtur nu va corect denit este posibil s primim rspunsuri eronate. Componenta logic a limbajului PROLOG este deci alegerea predicatelor si stabilirea relaiilor dintre datele descrise de aceste predicate. Controlul asupra modului de execuie al programului se a n felul n care sunt aranjate clauzele, dar i n cteva elemente de control structural cum este predicatul "cut" (notat "!") sau predicatul fail. Din aceste motive programarea logic este o abordare descriptiv, la care elementul structural imperativ este element de control. PROLOG-ul i versiunile sale (printre care i SWI-Prolog) face parte din categoria limbajelor de programare logice si este un limbaj declarativ ceea ce nseamn c mai degrab programatorul va scrie un program care conine o baz de date cu faptele i relaiile logice (regulile) dintre ele, astfel nct atunci cnd sistemului i se va adresa o ntrebare el va consulta baza de fapte i reguli pentru a gsi un rspuns (prin deducie logic). Programarea n PROLOG nu utilizeaz conceptele de procedur i atribuire, concepte foarte rspndite n alte limbaje de programare, n locul acestora ntlnim concepte proprii programrii logice. Faptul c nu exist atribuire se explic prin existena unei legturi (conceptul de unicare) ce se stabilete ntre valoare i variabil. Odat produs aceast legtur particip la un lan de deducii ce au loc pe parcursul programului, iar la terminarea lanului deductiv variabilele sunt dezlegate de aceste valori. Printre calitile PROLOG-ului se numra variabilele logice care se comport ca variabilele matematice, utilizarea backtrackingului pentru cutarea dovezi-

16

lor i pentru a se ajunge la o concluzie, structuri de date uniforme. n multe ocazii vor exista e mai multe ci de a gsi o soluie e mai multe soluii de aceea capabilitatea sistemului de a face backtracking se dovedete o caracteristic important. PROLOG-ul este un limbaj slab n ceea ce privete tipurile variabilelor, aceasta nseamn c o variabil de un anumit tip poate conine, la un moment dat, date de alt tip. Exemplele din acest material au fost concepute i testate n SWI-Prolog versiunea 5.4.3. 0.1.1.1 Structura programului

Aa cum am spus mai sus un program PROLOG const n fapte i reguli , care se pot grupa sub denumirea general de date, i ntrebri venite din partea utilizatorului, la care sistemul trebuie s rspund. Datele i ntrebarile sunt clauze Horn de forma: A(t1 , . . . , tn ) i n PROLOG ele sunt notate simbolic prin A(t1 , . . . , tn ). unde A este un predicat iar t1 , . . . , tn sunt constante ale limbajului predicatelor. Simbolul "." marcheaz nalul unei formule. O regul n PROLOG are forma: A(t1 , . . . , tn ) : B1 (p1 , . . . , pi ), . . . , Bn (q1 , . . . , qj ). 17

unde A, B1 , . . . , Bn sunt predicate, iar t1 , . . . , tn , p1 , . . . , pi , q1 , . . . , qj sunt termeni. Se spune adesea c regulile i faptele alctuiesc baza de date a programului. Interogrile sunt numite i scopuri i sunt clauze Horn de forma: B1 (s1 , . . . , si ), . . . , Bn (t1 , . . . , tj ) n PROLOG aceste clauze au forma: ? B1 (s1 , . . . , si ), . . . , Bn (t1 , . . . , tj ). unde B1 , . . . , Bn sunt simboluri de predicate, iar s1 , . . . , si , t1 . . . , tj sunt termeni. Aadar un program PROLOG este o colecie de fapte, reguli i interogri fr prea multe indicaii despre uxul i controlul programului. Aceast structur marcheaz neea cu care n acest limbaj pot obinute extensii i mbuntiri prin introducerea de fapte sau reguli fr a interveni asupra structurii si datelor deja existente n program. 0.1.1.2 Faptele

Faptele sunt cea mai simpl form de predicat n PROLOG. Ele sunt predicatele sau aciunile care se ntmpl far s depind de alte aciuni sau predicate. Faptele mai pot vzute i ca o baz de cunotine sau ca date de intrare. Sintaxa este urmtoarea: nume_predicat(param1, param2, ..., paramN ). 18

unde N este numrul de parametri ind numit aritatea predicatului. Un predicat de aritate 0 se denete astfel: nume_predicat. Exemple de fapte: ploua. - predicat de aritate 0 citeste(emil,literatura). - predicat de aritate 2 frati(emil,ion,george). - predicat de aritate 3 Alegerea numelor predicatelor precum i a interpretrii lor se face de ctre programator, este deci foarte important s se aleag nume care nu prezint ambiguiti i interpretarea unui predicat s se pstreze pe tot parcursul programului. Spre exemplu considerm predicatul bunic(dan, andrei). care are interpretarea "Dan este bunicul lui Andrei" dac vom mai avea un predicat bunic(marcel, gabi). pe care l interpretm "Gabi este bunicul lui Marcel". Programul scris de noi nu va ntoarce rezultatele ateptate deoarece interpretrile programatorului pentru acelai predicat sunt diferite, aceasta conducnd n mod indiscutabil la ateptri eronate cu privire la rezultatul care va obinut. 0.1.1.3 Regulile

O regul este o form de predicat care depinde de alte predicate pentru a ndeplinit. Sintaxa este urmtoarea : nume_predicat(arg1,arg2,...,argN):predicat1(param1,..,paramN), 19

predicat2(param1,..paramN), ..., predicatN(param1,...,paramN). Virgula n SWI-Prolog are valoarea unui i logic. Astfel n exemplul de mai sus ndeplinirea predicatului de argumente arg1,...,argN depinde de ndeplinirea tuturor celorlalte predicate, dac unul din ele ntoarce "No" nu se va mai trece la urmtorul predicat i nume_predicat va ntoarce i el "No". Exemple de reguli: frate(X,Y):parinte(Z,X), parinte(Z,Y). Aceast regul conine 2 predicate care trebuiesc ndeplinite pentru ca ea s se ndeplineasc. O posibil traducere a regulii n limbaj natural ar putea urmtoarea: X este frate cu Y dac exist Z care este printele lui X i Z este printe i pentru Y. picteaza(X):pictor(X), tablou(X,Z), critic_de_arta(Y), place(Y,Z). Regula de mai sus conine 3 sub-scopuri ea poate tradus dup cum urmeaz: X picteaz dac X este pictor i el are un tablou Z, Y este un critic de art i i place tabloul Z.

20

0.1.1.4

Comenzi n SWI-Prolog

Comenzile SWI-Prolog sunt la rndul lor predicate pe care sistemul le pune la dispoziia programatorului. O comand SWI-Prolog se termin ntotdeauna cu caracterul "." deoarece este considerat a un fapt. Iat cteva comenzi uzuale: ?-pwd. - aeaz directorul curent. ?-ls. - aeaz sierele din directorul curent. Directoarele vor avea caracterul nal "/" pentru a putea deosebite de iere. ?-cd(cale). - schimb directorul. ?-halt. - ncheie sesiunea de lucru. ?-help(nume_comand) - aeaz informaii despre nume_comand. ?- cd(c:/PROLOG). Yes ?- pwd. c:/PROLOG Yes ?- ls. alte ex/ L2ex4.pl L5ex1.pl L7ex4.pl L9ex2.pl grad.pl L2ex5.pl L5ex2.pl L7ex5.pl L9ex3.pl Yes. SWI-Prolog dispune de un browser de iere n mod grac, pentru ca 21

utilizatorul s nu e nevoit s vizualizeze structura de directorare i iere din linie de comand. Acest browser este util n special pentru editarea

ierelor .pl (surs SWI-Prolog ) care vor deschise cu utilitarul Notepad, dac un alt program de editare nu este congurat pentru a edita iere cu aceast extesie. Acesta poate accesat din meniul File, opiunea Navigator.

Pentru a ncrca un ier surs SWI-Prolog tastm comanda [numesier]., dac sistemul va rspunde cu "Yes", ierul a fost ncrcat cu succes, altfel vom primi un mesaj de genul "ERROR: source_sink numesier does not exist" n cazul n care ierul nu exist. Numele ierului trebuie scris cu litere mici, mai precis prima liter din nume, altfel SWI-Prolog va presupune c este vorba de o list i textul coninut nte paranteze este o variabil creia va ncerca s-i dea o valoare. n cazul unei erori de sintax n cadrul clauzelor scrise n ier mesajul arat n felul urmtor: "ERROR: c:/PROLOG/numesier.pl:2:8: Syntax error: Operator expected", calea

ctre ier poate alta n funcie de directorul unde se a ierul pe care dorim s-l compilm. O alt metod de a ncrca i compila un ier este folosirea predicatelor-sistem consult(numesier) i ensure_loaded(numesier). Exemple ale metodelor descrise sunt prezentate mai jos: ?- [l1ex1]. l1ex1 compiled 0.00 sec, 1,188 bytes Yes ?- ensure_loaded(l3ex1). % l1ex1 compiled 0.00 sec, 1,188 bytes 22

Yes ?- consult(l3ex1). % l3ex1 compiled 0.00 sec, 0 bytes Yes Pentru a verica ncrcarea corect a clauzelor putem folosi comanda listing, prezentat mai jos: ?-listing. fruct(prune). are(ion,mere). ...

0.1.2

Exemple

Exemplul 0.1.1. Fiierul L1ex1.pl conine clauzele: are(ion,mere). are(ana,prune). are(dan,bani). fruct(mere). fruct(prune). Pentru a vedea ce fel de fructe deine Ion vom apela predicatul are(), indicnd c vrem s am ce fel de fructe deine prin plasarea pe prima poziie a atomului "ion" i pe poziia secund variabila X ( variabilele ncep cu liter mare 23

n SWI-Prolog ). ?-are(ion,X). X=mere De data aceasta dorim s am dac Ion deine un fruct ns nu vrem s tim ce fel de fruct este. Pentru aceasta folosim underline "_" ( variabila underline n SWI-Prolog se numete variabil anonim, iar valorile coninute de aceast variabil nu sunt relevante pentru scopul urmrit atunci cnd se execut programul. Mai mult, dac n cadrul aceluiai program exit mai multe variabile "_" ele pot conine valori diferite n acelai timp fr s se afecteze reciproc. ). ?-are(ion,_). Yes n urmtorul exemplu dorim s am cine are mere i cine are prune. ?-are(X,mere),are(Y,prune). X=ion Y=ana Are cineva i mere i prune ? Observai faptul c fa de exemplul precendent primul parametru al predicatului are este aceeai variabil X, asfel dorim s desemnm faptul c este vorba de aceeai persoan care deine cele 2 tipuri de fructe. ?-are(X,mere),are(X,prune). No Are Dan fructe? Pentru a aa rspunsul trebuie mai nti s am dac Dan deine ceva. Folosim Predicatul are/2, punnd pe poziia secund variabila X,

24

care mai apoi ne ntrebm dac este fruct. Dac va denit un fapt de forma fruct(valoareaLuiX). rspunsul va armativ. ?-are(dan,X),fruct(X). No Are cineva ceva, dar nu fructe? De data aceasta negm predicatul fructe prin predicatul not care este un predicat predenit n SWI-Prolog. ?-are(X,Y),not(fruct(Y)). X=dan Y=bani Exemplul 0.1.2. Prezentm n continuare un exemplu de implementare a unui arbore genealogic. S observm faptul c numele personajelor ncep cu liter mic, aceasta deoarece ele sunt atomi (constante sau valori xate), dac am avut aceste nume cu liter mare compilatorul SWI-Prolog ar considerat c ele sunt variabile. Exemplul este implementat n ierul L1ex2.pl parinte(andrei,ionut). parinte(andrei,ilie). parinte(ilie,emil). parinte(ilie,irinel). Cine sunt copii lui andrei? n cazul acesta interogarea are dou rspunsuri, ns sistemul se va opri dup gsirea primei soluii i va atepta indicaii din partea noast. Dac dorim i aarea celuilalt rspuns trebuie s apsam ";", simbol care reprezint un sau logic. 25

?-parinte(andrei,X). X=ionut ; X=ilie ; No Are andrei vreun copil? ?-parinte(andrei,_). Yes Cine este tatl lui emil? ?-parinte(Tata,emil). Tata=ilie Dorim o enumerare a tuturor numelor care se a ntr-o relaie de tipul tatu. Pentru a obine toate rspunsurile i la aceast interogare apsai ";" dup ecare rspuns din partea sistemului. ?-parinte(X,Y). X = andrei Y = ionut ; X = andrei Y = ilie ; X = ilie Y = emil ; X = ilie Y = irinel ; Este andrei bunic? Avem din nou o interogare compus, observai din nou

26

poziia variabilei X. Pentru ca andrei s e bunic el trebuie s e parintele lui X ( parintele cuiva ) i acel cineva s aib un copil (nepotul lui andrei). Dup aarea tuturor soluiilor vom obine "No" deoarece sistemul ncearc s determine alte soluii pentru clauzele programului, considernd interogarea adresat. Alte de soluii neexistnd vom primi rspunsul No. ?-parinte(andrei,X),parinte(X,Nepot). X=ilie Nepot=emil; X=ilie Nepot=irinel; No Dac dorim s nu folosim o interogare compus putem edita ierul surs pentru a deni predicatul bunic(B, N ), prezentat mai jos, care va putea apoi apelat din linia de comand SWI-Prolog. bunic(B,N):-parinte(B,P),parinte(P,N). ?-bunic(andrei,irinel). Yes ?-bunic(andrei,Nepot). Nepot=emil Nepot=irinel No

27

0.1.3

Exerciii propuse

Exerciiul 0.1.1. Denii predicatele cumnat, matu, unchi, strabunic, soacr.

0.1.4

Teme de studiu

Tema 0.1.1. Rulai n SWI-Prolog exemplele prezentate.

28

0.2

Termeni.

Variabile.

Backtracking.

Predicatele-sistem trace, read, write


0.2.1
0.2.1.1

Fundamente teoretice
Termenii de baza n PROLOG

Un program SWI-Prolog este alctuit din predicate i n general se urmrete obinerea unui rspuns pentru o interogare. Fiecare predicat poate avea una sau mai multe clauze. Exemplul 0.2.1. masina(ferrari). masina(dacia). proprietar(george,ferrari). n exemplul de mai sus predicatul masina are dou clauze, iar predicatul proprietar are o singur clauz. O alt caracteristic a predicatelor este aritatea ( numrul de parametri sau termeni ). Termenii pot : - ntregi - numere pozitive sau negative. - Atomi - text care ncepe cu litera mic. Exemplu: ana, alt_atom, atom3, douaCuvinte, etc. 29

- Variabile - ncep cu litera mare sau "_". Exemplu: X, Y, _z, Variabila, Masina, Dan, Maria, etc. Structuri compuse ex. listele [a,b,c,d] sau tuplurile

carte(autor(nume),titlu,data). 0.2.1.2 Variabilele

Variabilele n SWI-Prolog ncep ntotdeauna cu liter mare sau "_" i sunt fr tip, adic pot conine orice fel de valoare. Totui iniial o variabil este doar un loc unde se va stoca la un moment dat n timpul procesrii unei clauze o valoare, care la momentul actual nu este disponibil. Spunem c variabila iniial nu este instaniat. Aceast funcie de loc de stocare a unei variabile poate exemplicat printr-un exemplu simplu: ?- X is 1+1. n cazul acesta rezultatul operaiei de adunare nu este cunoscut nainte ca expresia din dreapta lui "is" s e evaluat. Variabila X este deci iniial doar un loc rezervat pentru o valoare care va deveni disponibil dup evaluarea expresiei 1 + 1. Dac considerm un alt exemplu: ?- X = 1+1. vom observa c ntr-o variabil X, se pot pstra nu numai numere ntregi dar i structuri de date. n acest caz particular semnul "=" este un atom special care desemneaz egalitatea termenilor, de data aceasta 1 + 1 nu va mai considerat expresie i nu va mai evaluat, X va unicat cu o structur de 30

tipul 1 + 1. Aa cum am vzut n exemplele din seciunea anterioar valorile stocate n variabile pot recuperate n cadrul aceleiai interogri sau clauze, n exteriorul lor valorile se pierd, chiar dac numele variabilelor sunt aceleai. Aceasta ine de mecanismul de unicare Prolog, care face ca variabilele din cadrul altor clauze s e legate de alte locaii de memorie. ?- X = 1+2, Y is X. n acest exemplu X este instaniat cu termenul 1 + 2 si n interogarea care urmeaz se recupereaz din X expresia care va evaluat, n Y gsindu-se valoarea rezultat n urma evalurii, i anume 3. Un alt tip de variabile sunt variabilele anonime, acestea sunt desemnate de semnul "_" ( numai semnul acesta este o variabil anonim, _abc va considerat o variabil obinuit ) i valorile coninute de ele nu sunt relevante. Aceste variabile nu vor legate de valorile coninute, i o valoare a unei astfel de variabile nu va putea accesat deoarece dei reprezentarea este aceeai, linua de subliniere, ecare variabil anonim va desemna o alt zon de memorie, astfel printr-un predicat de genul write(_). nu vom primi rezultatul ateptat. Un concept important n PROLOG este acela de pattern sau model. De ecare dat cnd se ntlnete o variabil va cuta n baza de fapte i reguli o substituie pentru care predicatul ce conine variabila poate demonstrat prin deducie logic. Dac acest lucru nu este posibil sistemul va ntoarce "No." ca rspuns. S considerm urmtorul exemplu: Exemplul 0.2.2. 31

cuvant(buna). cuvant(ziua). fraza(A, B) :- cuvant(A), cuvant(B). salut(A, B) :- fraza(A, B), A = buna. Programul denete dou fapte (cuvant(buna). i cuvant(ziua).) i dou patternuri(fraza(. . . ) i salut(. . . )). ntlnind variabilele A i B compilatorul va ncerca s gseasc o substituie care s satisfac patternul sau modelul din dreapta semnului ":-" ( poate interpretat ca ind if-ul din programarea structurat ) , pentru acest caz particular avem substituiile: A=buna, B=buna A=buna, B=ziua A=ziua, B=ziua A=ziua, B=buna Pentru salut(A,B) ns vom avea o list de substituii mai scurt deoarece avem o condiionare n plus (A=buna) care reduce lista substituiilor care ndeplinesc patternul ( modelul ) impus. Pentru a obine totui o fraz de salut am putea aduga nc o condiionare i anume B=ziua. A=buna, B=buna A=ziua, B=ziua 32

Pentru a ilustra modul de utilizare a variabilelor anonime considerm programul precedent cu unele modicari. n cadrul predicatului fraza am adugat predicatul prieten(_). Acest predicat se va apela pentru toate predicatele din baza de fapte ns valorile din baza de fapte nu vor reinute n variabila _. Pentru a proba aceasta ncercai s folosii write(_) i urmrii rspunsul din partea sistemului. Exemplul 0.2.3. Fiierul L2ex1.pl conine programul de mai jos, tastai [l2ex1]. n linia de comand SWI-Prolog pentru a compila ierul: cuvant(buna). cuvant(ziua). prieten(andrei). prieten(alin). prieten(alex). fraza(A, B) :- cuvant(A), cuvant(B), prieten(_). salut(A, B) :- fraza(A, B), A = buna , B=ziua. Substituiile valide pentru exemplul de mai sus sunt n numar de 3 pentru A i B vom avea de ecare dat A=buna, B=ziua iar _ va avea pe rnd valorile andrei, alin, alex. 0.2.1.3 Comanda trace

La fel ca oricare alt mediu de programare SWI-Prolog ofer posibilitatea de a urmri execuia programului. Pentru a urmri un program relativ simplu, tot 33

ce trebuie s facei este s tastai trace. Cnd vei apela urmtorul predicat pentru care dorii un rspuns Prolog-ul va genera o list de apeluri de forma: Exit: (9) putere(ferrari, 500) ? creep Call: (9) put_min(gicu, _L204) ? creep Exit: (9) put_min(gicu, 300) ? creep Pentru a trece mai departe la apelul urmtor se apas tasta Enter sau Spaiu, cuvntul "creep" apare automat pentru a marca trecerea la apelul curent. Se poate urmri ns i execuia unui singur predicat prin apelul trace(NumePredicat). , de asemenea se poate urmri predicatul resDe exemplu

pectiv numai pentru anumite aciuni (call, redo, exit, fail).

trace(salut,+fail). va aa numai Fail-urile pentru predicatul salut. O comand de genul trace(salut). este echivalent cu trace(salut,+all). Putem opri trace-ul prin comanda trace(salut,-all). Evident trace(salut,-call). sau oricare alt opiune va opri trace-ul pentru acea opiune. Dac la un moment dat dorim s ntrerupem trace-ul denitiv dup ce am executat programul vom folosi predicatul nodebug. SWI-Prolog pune la dispoziie i un trace n mod grac, acesta se activeaz prin predicatul guitracer., iar la urmtorul apel al lui trace pentru un predicat se va deschide fereastra din gura 1. Dup cum se poate observa fereastra este mprit n 3 zone: n dreapta sus avem lista de apeluri, n stnga sus sunt enumerate variabilele i valorile de care sunt legate, iar jos se poate urmri locaia n surs care genereaz apelul curent. Predicatul noguitracer. oprete trace-ul grac.

34

Figura 1: Fereastra pentru trace n mod grac 0.2.1.4 Predicatele read/write

O alt abordare ecient pentru a aa ce se ntampl este aceea de a folosi predicatele din SWI-Prolog write(<mesaj>). i nl. Predicatul write va face s apar n fereastra SWI-Prolog mesajul <mesaj>, iar nl. va trece pe linie nou. Exemplul 0.2.4. Considerm programul de mai jos, implementat n ierul L2ex2.pl ingredient(zahar). ingredient(faina). cauta_ingredient(X):write(Caut: ), write(X), 35

nl, ingredient(X), write(am_gasit(X)), nl. Apel: ?- cauta_ingredient(zah). Caut: zah No ?- cauta_ingredient(zahar). Caut: zahar am_gasit(zahar) Yes Desigur n timpul execuiei unor programe dorim s citim variabile de la tastatur. SWI-Prolog pune la dispoziie predicatul-sistem read(<variabila>). Exemplul 0.2.5. Programul de mai jos exemplic modul de funcionare al predicatului read. Implementarea se gsete n ierul L2ex3.pl . Program: start:write(Introduceti o valoare: ), read(X),nl, write(Ati introdus: ), write(X). Apel: ?- start. 36

Introduceti o valoare: e345sd. Ati introdus e345sd Yes Comentariile n SWI- Prolog se fac n stilul C-ului /* comentariu */ sau comentarii pe un singur rnd, care ncep cu %, iar tot ce urmeaz pe linia respectiv va ignorat. Comentariile sunt utile ntotdeauna ntr-un cod surs, o convenie unanim acceptat este aceea de a pune comentarii naintea unui predicat SWI-Prolog pentru a-l explica. 0.2.1.5 Modul de funcionare SWI-Prolog Backtrackingul n acest paragraf urmrim s artm modul de funcionare al SWI-Prolog, felul n care rspunde interogrilor utilizatorului , deci felul n care ruleaz un program. Dndu-i-se o interogare Prolog-ul caut n lista sa de fapte i reguli (de sus n jos) cutnd n antetul faptelor i regulilor pe acelea care se potrivesc interogrii (avnd date un set de variabile legate), atunci cnd gsete un fapt sau o regul care se potrivete reine locul unde a ajuns n cutarea sa pentru ca apoi s revin n cazul n care regula se dovedete a imposibil de rezolvat prin deducie. S presupunem c avem urmtoarele fapte: Exemplul 0.2.6. Programul de mai jos se gsete n sierul L2ex4.pl . pasare(tip(canar), nume(tweety)). pasare(tip(pinguin), nume(tux)). 37

pasare(tip(pinguin), nume(bambi)). Pentru o interogare de forma ?- pasare(tip(pinguin), nume(X)). Prolog-ul va ncerca primul fapt din lista de fapte ns va ntoarce fail deoarece tipul psrii este canar i nu pinguin. Va trece mai departe i va ncerca s potriveasc cel de-al doilea fapt i atunci vom obine X=tux. Totui va pstra un pointer pentru locaia n care a ajuns pentru ca mai apoi s poat reveni n cazul n care o interogare sau un subscop va ntoace fail sau utilizatorul va cere un alt rspuns din partea sistemului apsnd ";". Atunci se va ncerca s se resatisfac predicatul pasare pentru X=bambi. S considerm acum un alt exemplu, avem baza de fapte/reguli de mai jos: Exemplul 0.2.7. Programul de mai jos se gsete n sierul L2ex5.pl . animal(leo). animal(spike). animal(tweety). animal(day). are_pene(tweety). are_pene(day). domestic(day). pasare(X):- animal(X), are_pene(X). pasare_domestica(X):- pasare(X), domestic(X). Dac vom adresa interogarea ?- pasare(P) se caut n baza de reguli i fapte pn se gsete predicatul pasare(X) i variabila P va instaniat ca variabila 38

X. Se trece apoi la corpul predicatului pasare(X) i se ncearc rezolvarea celor 2 predicate, pentru primul predicat animal(X) se va gsi valoarea X=leo. ns pentru aceasta nu exist un fapt are_pene(leo) sau un predicat, astfel se revine la ultimul predicat pentru care s-a ncercat s gseasc o potrivire ( i anume animal(X) ). Aciunile se repet i pentru X=spike. Cnd variabila predicatului animal(X) va identicat cu "tweety" din faptul animal(tweety), iar pentru predicatul are_pene(X), X va identicat cu "tweety" din faptul are_pene(tweety)., predicatul parare/1 va ntoarce "yes" pentru X=tweety. Dac tastm ";" atunci se va cuta o nou demonstraie i anume pentru X=day. Pentru o nou interogare , ?- pasare_domestica(X). compilatorul SWI-Prolog va ncerca mai nti s satisfac predicatul pasare(X), iar pentru X=tweety va ntoarce fail deoarece nu exist faptul domestic(tweety)., pentru nc o ncercare X=day. domestic(day). exist i raspunsul va X=day. n exemplul de mai sus am facut backtracking prin o baz de fapte ns de cele mai multe ori este nevoie de backtracking prin baza de reguli. S considerm exemplul urmtor: Exemplul 0.2.8. Programul de mai jos se gsete n sierul L2ex6.pl . animal(tweety). /* faptul 1 */ are_pene(tweety). /* faptul 2 */ pinguin(edgar). /* faptul 3 */ pinguin(allan). /* faptul 4 */ 39

domestic(allan). /* faptul 5 */ pasare(X):- pinguin(X). /* regula 1 */ pasare(X):- animal(X),are_pene(X). /* regula 2 */ pasare_domestica(X):- pasare(X), domestic(X). /* regula 3 */ Fie interogarea pasare(P). , se va apela prima regul care apeleaz pinguin(X). rspunsul va X=edgar. apoi se pune n aplicare backtrackingul i cel de-al doilea raspuns va X=allan. Dac se ncearc resatisfacera lui penguin(X). nu mai exist clauze pentru acest predicat asfel c se trece mai departe la regula 2 i se apeleaz animal(X) i are_pene(X) vom obine X=tweety.

0.2.2

Exerciii propuse

Exerciiul 0.2.1. Un om cumpar o main dac i place i dac poate s o ia. Unui om i place o main dac are puterea pe care i-o dorete. Un om poate s ia o main dac are destui bani n cont s o cumpere sau dac ind cstorit, soiei i place i ei maina i au mpreun bani s o cumpere.

0.2.3

Teme de studiu

Tema 0.2.1. Utilizai comanda trace pentru a urmri execuia programului de la exerciiul propus 0.2.1 .

40

0.3
0.3.1
0.3.1.1

Unicarea. Operaiile aritmetice


Fundamente teoretice
Unicarea

PROLOG-ul este un limbaj de programare cu trsturi mai puin obinuite : unicarea , backtrackingul i recursivitatea. Unicarea este partea PROLOGului care se ocup cu potrivirea patternurilor sau modelelor. Ideea din spatele acestui concept este simpl . S presupunem c avem predicatul culoare(X,Y), de asemenea avem o baz de fapte cu urmatoarea structur: culoare(masina, gri). culoare(semafor, verde). Pentru o interogare de forma ?- culoare(X,Y) variabilele X, i Y vor deveni variabile legate, X=masina i Y=gri, vom avea o potrivire a patternurilor. Aceasta pentru primul fapt dac apsm ";" atunci X i Y vor legate de valorile semafor i verde. Dar dac am avut un pattern de forma culoare(X, X) atunci o potrivire pentru acest pattern nu ar fost posibil. Potrivirea patternurilor se face ntre un scop i antetul unui fapt sau al unei reguli. Variabilele legate ale scopului sunt vericate cu cele din antetul regulii. Alte exemple: Dac avem predicatul carte(titlu(X),autor(nume(Nume), prenume(Pren))) la apelul lui pentru clauza de mai jos: carte(titlu(teoria_numerelor), autor(nume(georgescu), prenume(ionel))). 41

vom avea urmtoarele variabile legate: X Nume = = teoria_numerelor georgescu

Pren = ionel PROLOG-ul examineaz expresiile ntr-o manier pur structural, fr a face o evaluare a lor. Urmtoarele expresii sunt tratate n mod similar, n aceste cazuri semnul "=" nseamn "au o structur identic". ?- 1 + 2 = 3 No ?- X + 2 = 3Y . No Totui urmtoarele armaii sunt corecte deoarece au o structur asemnntoare. n aceste cazuri se va produce unicarea variabilelor cu valorile respective. ?- X + Y = 1 + 2. X=1 Y =2 ?- 1 + Y = X + 3. X=1 Y =3 Atomii diferii nu pot potrivii astfel pentru o interogare de forma andrei=alin. raspunsul primit va n toate situaiile No.

42

0.3.1.2

Operaii aritmetice

Funciile matematice din SWI-Prolog nu ntorc valori ci sunt evaluate cu o valoare corespunztoare. Predicatele din SWI-Prolog nu pot asemnate cu funciile din programarea structurat sau OOP, ele nu ntorc valori ! Dac se dorete s se obin anumite valori n urma apelului unui predicat atunci se vor aduga variabile n plus listei de parametri a acelui predicat, aceste variabile vor unicate cu valorile care se doresc a obinute nainte de ieirea din apelul predicatului. Aceasta se poate realiza prin scrierea unui pattern al predicatului n care numele variabilelor care conin valorile este scris pe poziia variabilelor libere adugate, astfel variabilele libere vor unicate cu valorile. Aceast adugare trebuie ns facut cu grij deoarece modicrile trebuie facute la nivelul ntregului program.

sin(X) cos(X)

sinus cosinus

asin(X) acos(X) atan(X)

arcsin arccos arctg

tan(X) tangenta

Tabela 1: Funcii trigonometrice disponibile n SWI-Prolog

Evaluarea expresiilor matematice n SWI-Prolog se face prin intermediul operatorului is. ?- X is 5+4. X=9 43

abs(X) round(X) exp(X) oat(X) sign(X) real(X) ceiling(X) integer(X) oor(X) ln(X),log(X),log10(X) sqrt(X)

modulul lui X rotunjire evalueaz e la puterea X ntoarce un oat ntoarce 1 pentru X pozitiv ntoarce un numr real primul ntreg mai mare ca X ntoarce un numr ntreg primul ntreg mai mic ca X evalueaz log din X radical din X

Tabela 2: Funcii matematice disponibile n SWI-Prolog ?-X is 5 4, Y is 2^3. X=20 Y=8 ?-X is 234556^100. Error 0:Arithmetic Overow

0.3.2

Exemple

Exemplul 0.3.1. Calculai aria i lungimea unui cerc de raza R. Rezolvarea n ierul L3ex1.pl 44

+ * / // ^

adunare scdere nmulire mprtire mprtire ntreag ridicare la putere

/\ \/ \ xor

i logic pe bii sau logic pe bii deplasare la stnga pe bii deplasare la dreapta pe bii complementul pe bii sau exclusiv pe bii

Tabela 3: Predicatele aritmetice in SWI-Prolog Apel: ?-aria. Dati raza unui cerc = 1. Aria cercului este 3.14 Lungimea cercului este 6.28 Program: aria:- write(Dati raza unui cerc = ), read(R),nl, write(Aria cercului este ), A is 3.14*R*R, write(A),nl, write(Lungimea cercului este ), L is 2*3.14*R, write(L),nl. Exemplul 0.3.2. 45

Vericai dac 3 numere sunt laturile unui triunghi. Rezolvarea n ierul L3ex2.pl Apel: ?- introdu. introdu a= 3. introdu b= 4. introdu c= 5. Aceste numere sunt laturile unui triunghi Program: introdu:write(introdu a= ),read(A), write(introdu b= ),read(B), write(introdu c= ),read(C), A>=0,B>=0,C>=0,A<(B+C),B<(C+A),C<(A+B), write(Aceste numere sunt laturile unui triunghi ),nl. Exemplul 0.3.3. Calculai media aritmetic a 2 numere. Rezolvarea n ierul L3ex3.pl Apel: ?-start1. HELLO X=4. Y=6. R=5. 46

yes Program: scrie1:- write(HELLO),nl. medie:- write(X=),read(X),write(Y=),read(Y), R is (X+Y)/2,write(R=),write(R). start1:- scrie1,medie,nl. Exemplul 0.3.4. Scriei un program SWI-Prolog care rezolv ecuaia de gradul 2. Rezolvarea n ierul L3ex4.pl Apel: ?- rezolva(1,4,-3). x1 = 0.645751 x2 = -4.64575 Program: rezolva(A, B, C) :Delta is B*B-4*A*C, % calculez delta caz(A, B, Delta), nl. caz(_, _, Delta) :Delta < 0, write("Nu are solutii reale"), !. caz(A, B, Delta) :Delta is 0, X is (-B)/(2*A), 47

write(x1=x2= ),write(X), !. caz(A, B, Delta) :SqrtDelta=sqrt(Delta), X1 is ((-B) + SqrtDelta)/(2*A), X2 is ((-B) - SqrtDelta)/(2*A), write(x1 = ),write(X1),nl, write(x2 = ),write(X2).

0.3.3

Exerciii propuse

Exerciiul 0.3.1. Scriei un predicat care calculeaz media geometric a dou numere introduse de la tastatur. Rezultatul va scris pe ecran.

0.3.4

Teme de studiu

Tema 0.3.1. Urmrii cu trace programele prezentate pentru a nelege modul n care se evalueaz expresiile aritmetice.

48

0.4
0.4.1
0.4.1.1

Recursivitate. Predicatele !(cut) i fail


Fundamente teoretice
Recursivitatea

Recursivitatea este o tehnic des ntlnit n mediile Prolog. Acest termen, recursivitate, nseamn c un predicat este denit de mai multe ori i se auto-apeleaz. Iat un exemplu simplu de recursivitate: strabun(Bunic,Nepot) :parinte(Bunic,Nepot). strabun(Bunic,Nepot) :parinte(Bunic,Tata), strabun(Tata,Nepot). Toate deniiile recursive trebuie s conin cel puin 2 clauze clauza de baz i clauza recursiv. n clauza de baz trebuie s ne asigurm c exist o condiie de oprire i c exist cel puin o soluie n cadrul recursivitii. Clauza recursiv este cea care reapeleaz predicatul, observai faptul c parinte/2 se apeleaz nainte ca predicatul strabun/2 s se auto-apeleze. Dac vom modica programul de mai sus i l vom pune sub forma urmtoare (implementarea n ierul L4ex1.pl):

49

parinte(emilia,maria). parinte(ion,maria). parinte(maria,petre). strabun(Bunic,Nepot) :strabun(Tata,Nepot), parinte(Bunic,Tata). strabun(Bunic,Nepot) :parinte(Bunic,Nepot). vom observa c ordinea n care se face apelul predicatelor este important deoarece dei deniia programului este logic corect acesta pentru interogarea ?- strabun(X,petre). nu va ajunge la o soluie.

0.4.1.2 Cut

Predicatele !(cut) i fail

Cut este un predicat predenit notat prin "!" n SWI-Prolog, totdeauna adevrat i care acioneaz asupra motorului de inferene. Cu ajutorul lui este posibil s controlm modul n care lucreaz backtrackingul. Folosirea acestui predicat ntr-o clauz are urmtoarele efecte: 1. Poate s foreze eecul unei clauze, deoarece dup apelul lui clauzele care l succed nu se vor mai executa. 2. Poate limita numrul de soluii prin reducerea arborelui de inferen, n acelai timp ind posibil oprirea cutrii de soluii pe unele ramuri n cazul n care programatorul tie c pe ramurile respective nu sunt soluii. 50

Exemplul de mai jos prezint funcionarea unui program fr predicatul cut. De observat este faptul c n predicatul test, prima clauz apeleaz predicatul conditie, el se va apela pentru ecare din cele 3 clauze. Observai ce se ntmpl n momentul n care adugm "!" n predicatul test dup apelul predicatului conditie. Implementarea acestor predicate se gseste n ierul L4ex2.pl Apel: ?- start. unu doi trei clauza doi predicatul test No Program: conditie(unu). conditie(doi). conditie(trei). test(X) :conditie(X). test(clauza doi predicatul test). start:test(X), write(X), nl, fail. Modicm programul de mai sus astfel:

51

test_cut(X) :conditie(X),!. test_cut(clauza doi test). start_cut:- test_cut(X), write(X), nl, fail. Rezultatul va urmtorul: ?- start_cut. unu No Modicm exemplul de mai sus astfel: test_cut2(X,Y,Z,K) :conditie(X),conditie(Y),!,conditie(Z),conditie(K). test_cut2(clauza doi test). start_cut2:- test_cut2(X,Y,Z,K), write(X - Y - Z - K), nl, fail. n aceast ultim modicare se observ cel mai bine rolul pe care l are cut. Deoarece este plasat dup al doilea apel al predicatului conditie nu se va mai ncerca resatisfacerea primelor predicate conditie i pentru celelalte valori(respectiv "doi" i "trei"). Altfel spus nu se va ncerca resatisfacerea predicatele conditie(X) si conditie(Y) pentru alte valori dect cele de "unu". Rezultatul este urmtorul: ?- start_cut2. unu-unu-unu-unu unu-unu-unu-doi unu-unu-unu-trei unu-unu-doi-unu

52

unu-unu-doi-doi unu-unu-doi-trei unu-unu-trei-unu unu-unu-trei-doi unu-unu-trei-trei No Considerm n continuare o alt implementare pentru a exemplica predicatul cut. Predicatele de mai jos se gsesc implementate n ierul L4ex3.pl Apel: ?- este_in_forma(X,Y). X = andrei Y = nesatisfacatoare; No Program: este_in_forma(Sportiv, nesatisfacatoare) :max_otari(Sportiv,P), P < 15,!. este_in_forma(Sportiv, satisfacatoare). max_otari(ionel,20). max_otari(andrei,12). max_otari(daniel,25). max_otari(alin,10). Cut-ul din prima clauz inseamn "dac ai ajuns pn aici atunci renun s

53

mai caui alte soluii". Cut-ul este o metod des utilizat ns n acest caz distruge citirea logic a clauzelor care l conin. Spre exemplu clauza de mai sus ar putea interpretat "Nu este n form sportivul care nu poate face mai mult de 15 otri" ns cut-ul nlocuiete negaia i foeaz ncheierea execuiei programului. Observai c dei mai sunt soluii n baza de fapte pentru interogare primim rspunsul No.

Fail Cnd un subscop al unui predicat ntoarce "fail" PROLOG ncearc prin backtracking s resatisfac toate subscopurile acelui predicat. Este acelai lucru cu a apsa ";" atunci cnd dorim s obinem un nou rezultat pentru o problem , dac el exist. Exist un predicat (fail) predenit, care ntoarce fail n orice ocazie, cauznd astfel backtrakingul. Iat un exemplu de utilizare a predicatului fail/0 (nu are argumente).Exemplul este implementat n ierul L4ex4.pl Apel: ?- plante(_). cartof cires garoafa cus Yes

54

Program: planta(cartof). planta(cires). planta(garoafa). planta(cus). plante(X):- planta(X),write(X),nl,fail. plante(_). Predicatul plante(X) din programul de mai sus, datorit subscopului fail, va ntoarce el nsui fail, astfel se va ncerca resatisfacerea sa pentru alte valori ale variabilei X. Cnd nu mai exist astfel de valori a doua clauz a predicatului este ncercat, aceasta ind un fapt ce are ca parametru o variabil anonim va ntoarce Yes. Un exemplu interesant este urmtoarea bucat de cod, n care folosind o combinaie cut/fail putem nlocui cu succes negaia. nuestecopil(X, Y) :- copil(X, Y), !, fail. nuestecopil(X, Y).

Este acelai lucru cu nuestecopil(X, Y) :- not(copil(X, Y)). deoarece n cazul n care copil (X,Y) ntoarce "Yes" cut oprete backtrackingul, iar fail ntoarce "No", facnd asfel ca nuestecopil(X, Y) s ntoarc imediat "No". n cazul n care copil(X,Y) ntoarce "No" atunci nuestecopil(X,Y) va ntoarce "Yes" pentru a 2-a clauz.

55

0.4.2

Exemple

Exemplul 0.4.1. 0.4.2.1 Funcia factorial

Scriei un program Prolog care calculeaz funcia factorial pentru un n dat. Implementare n ierul L4ex5.pl Pentru a calcula factorialul unui numr tim urmtoarele lucruri: 1 0! = 1 i 1! = 1 2 n! = n(n 1)! Aa cum am spus mai sus recursivitatea se realizeaz prin mai multe clauze ale aceluiai predicat, astfel condiiile de mai sus se pot traduce astfel: 1 condiia de oprire i n acelai timp o valoare cunoscut pentru funcia factorial 2 este condiia de recursie Apel: ?-fact(3,R). R=6 Yes Program: fact(0,1). fact(N,R):-fact(N1,R1),N is N1+1,R is R1N. 56

Rezolvarea prezentat se numete "calculul factorialului pe retur", deoarece valoarea lui R (defapt valoarea lui N factorial)va calculat la revenirea din apelurile succesive pentru resatisfacerea lui fact(N1,R1). S urmrim execuia programului de mai sus cu trace pentru a observa mai bine modul de lucru al SWI-Prolog. ?- trace,fact(3,R). <- apelul predicatului Call: (9) fact(3, _G461) ? creep <- nu se intra pe prima ramur fact(0,1) deoarece nu se potrivete antetul predicatelor (avem apel pentru fact(3,R)), acesta este apelul pentru fact(N,R) Call: (10) fact(_L215, _L216) ? creep <- apel fact(N1,R1) Exit: (10) fact(0, 1) ? creep <- unicare cu fact(0,1) ^Call: (10) 3 is 0+1 ? creep <- veric dac N is 0+1, adic _L215+1 ^Fail: (10) 3 is 0+1 ? creep <- fail Redo: (10) fact(_L215, _L216) ? creep <- se ncearc resatisfacerea lui fact(N1,R1) pentru alte valori Call: (11) fact(_L234, _L235) ? creep <- se reapeleaz predicatul fact pentru alte variabile care nu sunt legate Exit: (11) fact(0, 1) ? creep <- unicare cu fact(0,1) ^Call: (11) _L215 is 0+1 ? creep <- variabilele din primul set vor lua alte valori ^Exit: (11) 1 is 0+1 ? creep ^Call: (11) _L216 is 1*1 ? creep ^Exit: (11) 1 is 1*1 ? creep

57

Exit: (10) fact(1, 1) ? creep <- se iese din apelul de la (10) adugndu-se fact(1,1) la baza de fapte i se veric din nou dac N is N1+1 ^Call: (10) 3 is 1+1 ? creep ^Fail: (10) 3 is 1+1 ? creep Redo: (11) fact(_L234, _L235) ? creep <- se ncearc din nou satisfacerea lui fact(N1,R1) ns pentru un al treilea set de variabile Call: (12) fact(_L246, _L247) ? creep <- din nou unicare cu fact(0,1) Exit: (12) fact(0, 1) ? creep <- unicarea variabilelor din setul 3 cu valorile 0 i respectiv 1 ^Call: (12) _L234 is 0+1 ? creep <- variabilele din setul 2 vor lua alte valori 1 i respectiv 1 ^Exit: (12) 1 is 0+1 ? creep ^Call: (12) _L235 is 1*1 ? creep ^Exit: (12) 1 is 1*1 ? creep Exit: (11) fact(1, 1) ? creep <- se revine din Redo pentru pasul (11) i variabilele din setul 1 ia valorile 2 i respectiv 2 ^Call: (11) _L215 is 1+1 ? creep ^Exit: (11) 2 is 1+1 ? creep ^Call: (11) _L216 is 1*2 ? creep ^Exit: (11) 2 is 1*2 ? creep Exit: (10) fact(2, 2) ? creep <- la revenirea la pasul(10) N va N1+1 i se trece mai departe i se calculeaz rezultatul nal. ^Call: (10) 3 is 2+1 ? creep

58

^Exit: (10) 3 is 2+1 ? creep ^Call: (10) _G461 is 2*3 ? creep ^Exit: (10) 6 is 2*3 ? creep Exit: (9) fact(3, 6) ? creep <- iesire din apel R=6 Yes Exemplul 0.4.2. Factorial calculat pe tur: Apel: ?- fact2(4,R). R = 24 Yes Program: fact2(N,N,R,R). fact2(N,N1,R1,R):- N2 is N1+1, R2 is R1*N2 , fact2(N,N2,R2,R). fact2(N,R):- fact2(N,1,1,R). Apelul se face asemntor primului program , din fact2(N,R) apelm pe fact2(N,N1,R1,R) , N1 ind un N intermediar pentru a ti cnd s ne oprim, iar R1 este un rezultat intermediar care atunci cnd se va ajunge la N1 = N va unicat cu R prin faptul fact2(N,N,R,R). care este i condiia de oprire pentru obinerea rezultatului nal. S urmrim trace-ul pentru acest program: ?- trace,fact2(4,R). <- apel Call: (8) fact2(4, _G283) ? creep <- predicatul care apeleaz pe

fact2(N,N1,R1,R) 59

Call: (9) fact2(4, 1, 1, _G283) ? creep <- apel fact2(N,N1,R1,R) ^Call: (10) _L196 is 1+1 ? creep <- calcul N1 ^Exit: (10) 2 is 1+1 ? creep <- ieire calcul N1 ^Call: (10) _L197 is 1*2 ? creep <- calcul R1 ^Exit: (10) 2 is 1*2 ? creep <- ieire calcul R1 Call: (10) fact2(4, 2, 2, _G283) ? creep <- se reapeleaz pentru noile valori ^Call: (11) _L217 is 2+1 ? creep <- calcul N1 ^Exit: (11) 3 is 2+1 ? creep <- ieire calcul N1 ^Call: (11) _L218 is 2*3 ? creep <- calcul R1 ^Exit: (11) 6 is 2*3 ? creep <- ieire calcul R1 Call: (11) fact2(4, 3, 6, _G283) ? creep <- se reapeleaz factorial ^Call: (12) _L238 is 3+1 ? creep <- calculul valorilor intermediare ^Exit: (12) 4 is 3+1 ? creep ^Call: (12) _L239 is 6*4 ? creep ^Exit: (12) 24 is 6*4 ? creep Call: (12) fact2(4, 4, 24, _G283) ? creep Exit: (12) fact2(4, 4, 24, 24) ? creep <- ieire din factorial Exit: (11) fact2(4, 3, 6, 24) ? creep Exit: (10) fact2(4, 2, 2, 24) ? creep <- observai c valorile lui R intermediar se pierd Exit: (9) fact2(4, 1, 1, 24) ? creep Exit: (8) fact2(4, 24) ? creep R = 24

60

Yes Exemplul 0.4.3. 0.4.2.2 Cmmdc i Cmmmc

Scriei un program Prolog care calculeaz cmmdc i cmmmc pentru dou numere X i Y. Implementarea se gsete n ierul L4ex6.pl Prezentm algoritmul lui Euclid pentru cel mai mare divizor comun (cmmdc) i cel mai mic multiplu comun (cmmmc). Apel: ?- cmmdc(6,15,X). X=3 ?-cmmmc(6,7,Y). Y=42

61

Program: cmmdc(X,0,X). cmmdc(X,Y,D):- R is X mod Y, cmmdc(Y,R,D). cmmmc(X,Y,M):- cmmdc(X,Y,D),M is (XY)/D. Programul denete cmmdc(X,Y,D) ca ind clauza recursiv, n interiorul ei vom calcula restul conform algoritmului lui Euclid i vom reapela cmmdc pentru Y,R i o a 3-a variabil D, iar cmmdc(X,0,X) este clauza de oprire a recursivitii, la nal cnd aceast clauz este apelat, variabilele de pe prima i ultima poziie vor unicate i vom obine cmmdc. ?- trace,cmmdc(14,8,R). <- apel cmdc Call: (9) cmmdc(14, 8, G492) ? creep <- intr pe clauza 2 ^Call: (10) L218 is 14 mod 8 ? creep <- se calculeaz R ^Exit: (10) 6 is 14 mod 8 ? creep Call: (10) cmmdc(8, 6, G492) ? creep <- se reapealeaz cmmdc pentru alte valori ^Call: (11) L237 is 8 mod 6 ? creep <- calculeaz din nou R ^Exit: (11) 2 is 8 mod 6 ? creep Call: (11) cmmdc(6, 2, G492) ? creep <- se reapealeaz cmmdc pentru alte valori ^Call: (12) L256 is 6 mod 2 ? creep <- calculeaz din nou R ^Exit: (12) 0 is 6 mod 2 ? creep Call: (12) cmmdc(2, 0, G492) ? creep <- de data aceasta se intr pe clauza cmmdc(X,0,X)

62

Exit: (12) cmmdc(2, 0, 2) ? creep <- pe poziia secund vom avea tot X i se revine din calcul Exit: (11) cmmdc(6, 2, 2) ? creep Exit: (10) cmmdc(8, 6, 2) ? creep Exit: (9) cmmdc(14, 8, 2) ? creep R=2 Yes Exemplul 0.4.4.

0.4.2.3

N la puterea K

Scriei un program prolog care calculeaz N la puterea K. Implementarea n ierul L4ex7.pl Apel: ?-puterea(2,3,R). R=8

Program: puterea(N,K,R,K,R). puterea(N,K,R,K1,Rez):- K2 is K1+1, R1 is N*R ,puterea(N,K,R1,K2,Rez). puterea(N,K,R):-puterea(N,K,1,0,R). Rezolvarea de mai sus este un exemplu "de calcul pe tur". Ideea din spatele programului este de a calcula n dou variabile K2 i R1 puterea la care s-a ajuns i respectiv rezultatul intermediar.Astfel condiia de oprire este 63

puterea(N,K,R,K,R). cnd se ajunge la puterea K (observai cele 2 perechi de variabile identice , K i R) acesta este un fapt i valoarea din prima variabil R este unicat cu variabila a doua R. Urmrii cu trace modul de lucru al acestui program.

0.4.3

Exerciii propuse

Exerciiul 0.4.1. Scriei predicatul puterea(N,K,R) care returneaz n variabila R pe N la puterea K, cu calculul puterii pe retur.

0.4.4

Teme de studiu

Tema 0.4.1. Rulai pas cu pas programele prezentate n exemplele de mai sus ct i pe cele propuse ca exerciii.

64

0.5

Turnurile din Hanoi. Funciile Fibonacci i Ackermann

0.5.1

Fundamente teoretice

Prezentm n continuare cteva probleme cunoscute ale programrii structurate i modul n care sunt ele abordate n programarea logic i mediul SWIProlog.

0.5.2

Exemple

Exemplul 0.5.1. 0.5.2.1 Turnurile din Hanoi

Exista 3 turnuri , stnga, centru, dreapta, pe cel din stnga se gasesc N discuri de mrimi diferite suprapuse descresctor de la baz spre vrf. Cum pot mutate cele N discuri de pe turnul din stnga pe cel din dreapta, folosind turnul din centru, astfel nct s e ndeplinite urmtoarele condiii: - la ecare operaie de mutare se mut un singur disc. - discurile ind de dimensiuni diferite, un disc oarecare nu poate pus peste altul mai mic. La fel ca n cazul funciei factorial avem nevoie de un caz de baz i un caz general care poate exprimat prin operaii de o complexitate redus. Pentru 65

a sublinia faptul c mutm un disc folosim predicatul muta(A,B) care nseamn mut primul disc de sus de pe turnul A pe turnul B. De ecare dat cnd mutm un disc acest predicat va aa mesajul corespunztor prin intermediul predicatului write. Cazul de baz. Un caz de baz este mutarea unui singur disc de pe turnul A(stnga) pe trunul B(dreapta) folosind turnul C(centru). Pentru aceasta am putea folosi predicatul hanoi(1, A, B, C):- muta(A,B), defapt pe lng acest caz exist un caz mult mai simplu i anume acela n care nu mutm nici un disc , pentru acesta vom folosi predicatul hanoi(0, _ , _ , _ ):- !. Cazul recursiv Pentru cazul inductiv trebuie s transferm N discuri de pe A pe B, presupunem c avem deja un program care transfer N-1 discuri . Paii pe care i urmm sunt urmtorii : 1. Transferm primele N-1 discuri de pe A pe C 2. Transferm ultimul disc de pe A pe B 3. Transferm N-1 discuri de pe C pe B n implementare predicatul corespunztor operaiilor de mai sus este hanoi(N, A, B, C) Programul este urmatorul: (implementarea n ierul L4ex7.pl) start(N) :- hanoi(N, stanga, centru, dreapta). hanoi(0, _ , _ , _ ):- !. hanoi(N, A, B, C):- /*mut de pe A pe B folosind C*/ 66

N_1 is N-1, hanoi(N_1, A, C, B), /*mut de pe A pe C folosind B - pasul 1*/ muta(A, B),/*mut de pe A pe B ultimul disc - pasul 2*/ hanoi(N_1, C, B, A). /*mut de pe C pe B folosind A - pasul 3*/ muta(F, T) :- write(muta, F, >, T), nl. Apel: start(3). Rezultatul va urmtorul: muta, stanga, (>), centru muta, stanga, (>), dreapta muta, centru, (>), dreapta muta, stanga, (>), centru muta, dreapta, (>), stanga muta, dreapta, (>), centru muta, stanga, (>), centru

0.5.2.2

Modul de funcionare al programului:

Se va apela cu start(N)., unde N este un numr natural. Pentru clauza start se va apela predicatul hanoi(N, stanga, centru, dreapta). care apeleaz primul predicat hanoi ntlnit, nu va intra pe ramura hanoi(0,_,_,_) deoarece patternurile nu sunt identice, i anume N este diferit de 0 i celelalte variabile nu sunt libere, merge mai departe la urmtoarea clauz, aici va decrementa pe N pn la 0 , va intra pe clauza hanoi(0,_,_,_) unde va face cut, iar pe recursie 67

va aa modul de aranjare a discurilor. Exemplul 0.5.2. 0.5.2.3 irul lui Fibonacci

S se deneasc un predicat care pentru un N dat s calculeze termenul de rang n din irul lui Fibonacci. Implementarea se gsete n ierul L5ex1.pl Indicaii: Un termen din irul lui Fibonacci se calculeaz conform relaiei de recuren n 2 pai: - f(1)= f(2)= 1 - f(n)= f(n-2) + f(n-1), daca n>=3 irul lui Fibonacci arat astfel: - 1, 1, 2, 3, 5, 8, 13, 21, 34, 55... Apel: ?-b(6,R). 13

68

Program: b(1,1). b(2,1). b(N,R):- N>=3,N1 is N-1,N2 is N-2, b(N1,R1),b(N2,R2),R is R1+R2. Exemplul 0.5.3.

0.5.2.4

Funcia Ackermann

Funcia Ackermann este denit recursiv pentru numere ntregi pozitive. Este o funcie ale crei valori cresc foarte repede devenind att de mari nct este imposibil s e calculate. De fapt, se spune c scrierea lor sub form zecimal nu poate stocat n tot universul zic. Ca un exemplu A(4,2) este mai mare dect numrul tutror particulelor din univers ridicate la puterea 200. Funcia a fost decoperit n 1928 de Wilhelm Ackermann (1896 - 1962) sub o alt form i este un exemplu de funcie recursiv care nu este ns o funcie primitivrecursiv (exemple de funcii primitiv-recursive: funcia constant egal cu 0, funcia succesor). Este util n special la testarea compilatoarelor pentru a verica puterea de recursie a acestora. Spre exemplu dac un compilator este capabil s salveze valori ale lui A(2,n) i A(3,n) pentru a calcula pe ... s spunem A(3,30) atunci el va reduce numrul computaiilor cu un factor de ordinul sutelor de mii. Exist i o invers a funciei Ackermann care spre deosebire de aceasta crete foarte ncet, defapt maximul ei este o valoare mai mic dect 5 pentru 69

m/n 0 1 2 3 4 5 6

0 1 2 3 5 13 65533 A(5,1)

1 2 3 5 13 65533 A(4,65533)

2 3 4 7 29 265536 3

3 4 5 9 61

4 5 6 11 125

A(3,A(4,2)) A(3,A(4,3))

A(4,A(5,1)) A(4,A(5,2)) A(4,A(5,3))

A(5,A(5,1)) A(5,A(6,1)) A(5,A(6,2)) A(5,A(6,3))

Tabela 4: Cteva valori ale funciei Ackermann orice valori de intrare posibile. Trebuie reinut faptul c aceasta nu este inversa funciei Ackermann n sensul strict matematic. Deniie formal: f (m, n) = min{i?1 : A(i, f loor(m/n)) > log2 n} unde A(i,j) este funcia Ackermann. Deniia funiei Ackermann: Ack(0,n) = n+1 Ack(m,0) = Ack(m-1,1) pentru m >0 Ack(m,n) = Ack(m-1,Ack(m,n-1)) pentru m,n>0 Apel: ?- ack(3,5,R). R = 253 70

m n 0 1 1 2 2 2 3 3 3 1 1 2 1 2 3 2 3 4

ack(m,n) 2 3 4 5 7 9 29 61 stack overow

A(m,n) n general n+1 n+2

2n+3

8 2n 3

Tabela 5: Valorile funciei Ackerman calculate n SWI-Prolog ?- ack(3,6,R). ERROR: Out of local stack ?- ack(4,5,R). ERROR: Out of local stack Programul: ack(0,M,R):-R is M+1,!. ack(N,0,R):-R1 is N-1,ack(R1,1,R). ack(N,M,R):-N1 is N-1,M1 is M-1,ack(N,M1,R1),ack(N1,R1,R).

0.5.3

Exerciii propuse

Exerciiul 0.5.1. 71

Scriei predicatul PROLOG b(N,R) care returneaz n variabila R termenul N din irul lui Fibonacci i care calculeaz acest termen pe tur. Exerciiul 0.5.2. Scriei predicatul PROLOG ackermann(N,M,R) care returneaz n variabila R rezultatul funciei Ackermann, calculat pe tur.

0.5.4

Teme de studiu

Tema 0.5.1. Studiai cu trace. evoluia programelor prezentate ct i a celor de la "Exerciii propuse".

72

0.6
0.6.1

Liste
Fundamente teoretice

Listele n mediile Prolog sunt o secven ordonat de termeni, conceptual nu exist prea multe asemnri ntre listele din PROLOG i irurile din C. Iat cteva exemple de liste: [] - lista vid [a,c,s,f,d,h,q,p] - list cu 8 elemente [carne, lapte, legume, fructe] - list cu 4 elemente [pornit(motor), arde(benzina), conduc(masina)] - lista cu 3 elemente ( cele 3 elemente termeni ) [1,a,[1,c,f,2],[nume(carte),1,a,oare]] - exemplu de list n list, cu elemente diferite, care sunt ns atomi. Deoarece listele sunt structuri ordonate de termeni lista [1,a,b] va diferit de [a,1,b]. 0.6.1.1 Accesarea elementelor din list

Accesul la elementele din list se produce secvenial, adic pentru a ajunge la elementul N din list trebuie s eliminm din list primele N-1 elemente. Am spus "eliminm" deoarece odat accesat un element din list nu va mai aparine de lista respectiv. Scoatem un element din list n felul urmator 73

[Element|Coada], elementul Element va unul din atomii listei , iar Coada va restul listei care poate procesat n continuare.

Extragerea unui element ?- [Element|Coada]=[mere,prune,caise,cirese]. Element = mere Coada = [prune, caise, cirese]

Introducerea unui element ?- L=[1,2],R=[a,b,c|L]. L = [1, 2] R = [a, b, c, 1, 2]

0.6.2

Exemple

Exemplul 0.6.1. Scriei n ordine invers elementele unei liste. Implementarea se gsete n ierul L6ex1.pl Apel: ?-scrie([a,b,c]). cba Yes

Program: 74

scrie([]). scrie([X|R]):-scrie(R),write(X),write( ). Programul funcioneaz pe baza recursiei. Predicatul scrie mparte lista n cap i coad n antetul clauzei sale i se reapeleaz pentru coada listei,R. Prima clauz a acestui predicat este un fapt ce va ntoarce Yes atunci cnd lista va vid. n acel moment se va reveni din apelurile succesive ale predicatului i pe ntoarcere vor scrise elementele X extrase din list. Exemplul 0.6.2. Vericai dac o list are un numar par de elemente. Implementarea se gsete n ierul L6ex2.pl Apel: ?-par([a,b,c,d]). Yes Program: par([_,_]). par([_,_|T]):-par(T). Predicatul par/1 este un predicat recursiv, se scot cte 2 elemente din list n dou variabile anonime, deoarece nu ne intereseaz elementele coninute de list. La nal, dac vor rmne 2 elemente care pot scoase din list atunci n lista exist un numr par de elemente, altfel predicatul va returna Fail. Exemplul 0.6.3. Scriei un predicat care returneaz numrul de elemente dintr-o list. Implementarea se gsete n ierul L6ex3.pl 75

Exista i predicatul sistem(built-in): length(Lista,Nr). care ntoarce n Nr numrul elementelor din list. Apel: ?-lungime([a,b,[c,d],e],R). R=4 ?-length([a,b,[c,d],e],R). R=4 Program: lungime([],0). lungime([_|T],R):-lungime(T,R1),R is R1+1. tim ca n lista vid sunt 0 elemente, extragem cte un element din list i reapelm predicatul pentru coada listei i la revenirea din apelurile succesive numrm elementele. Exemplul 0.6.4. Vericai dac un element aparine unei liste. Implementarea se gsete n ierul L6ex4.pl Apel: ?-member(b,[a,v,b,c]). Yes ?-member(a,[b,c,g]). No Program: member(X,[X|_]). 76

member(X,[_|T]):-member(X,T). Predicatul member este tot un exemplu de predicat recursiv. Aceast deniie poate asemnat cu un if din programarea structurat. n antetul predicatului se extrage din list un element, dac elementul extras este X, atunci predicatul ntoarce Yes. Altfel vor scoase elemente din list pn cnd n cele din urm lista va vid si memeber/2 va ntoarce Fail. Exemplul 0.6.5. Vericai dac o list este sau nu mulime. O list care este considerat mulime conine elemente care nu se rept. Implementarea se gsete n ierul L6ex5.pl Apel: ?-set([a,b,c,c,d]). No set([a,b,c]). Yes Program: set([]). set([X|T]):-not(member(X,T)),set(T). i acest predicat este unul recursiv. Se extrag elemente din list i se veric dac elementul extras este membru pentru coada listei. Ne oprim atunci cnd lista este vid, caz n care lista este o mulime, deoarece toate elementele au fost extrase i niciunul nu a fost membru n coada listei. Dac un element ar fost membru n restul listei atunci predicatul member negat prin not ar 77

ntors fail i am primit rspunsul No. Exemplul 0.6.6. Scriei un predicat care face nmulirea a 2 vectori. Implementarea se gsete n ierul L6ex6.pl Apel: ?-prodv([1,2,4],[3,2,3],R). R=[3,4,12] Yes Program: prodv([X],[Y],[R]):-R is X*Y. prodv([H|T],[H1|T1],[R|R1]):prodv(T,T1,R1), R is H*H1. Gestionm 3 liste, 2 din ele reprezint coordonatele vectorilor iar n ultima avem rezultatul, scoatem elemente din primele 2 liste pn cand vom rmne cu un singur element n ecare , atunci ultima coordonat a vectorului rezultat este X*Y i pe ntoarcere calculm celelalte componente. Exemplul 0.6.7. Scriei un predicat care gsete ultimul element al unei liste. Implementarea se gsete n ierul L6ex7.pl Apel: ?- last([a],R) 78

R=a ?-last([a,b,1,c],X). X=c ?-last([a,b,[c,[d]]],X). X=[c,[d]] Program: last([X],X). last([H|T],R):-last(T,R). Scoatem elemente din list pn cand n list vom avea un singur element pe care l unicm cu variabila liber X. Exemplul 0.6.8. S vericm dac o mulime intr n toate mulimile unei liste de mulimi. Implementarea se gsete n ierul L6ex8.pl Apel: ?-inclus([a,b],[1,a,c,b]). Yes ?-inclus([],[a,b]). Yes ?-inclus_multimi([a,b,c],[[a,b,c,d],[m,a,b,c]]) Yes Program: inclus([],L). inclus([H|T],L):- member(H,L),inclus(T,L). 79

Orice mulime include mulimea vid: dac lista este vid ntoarce lista L. mpart lista n cap i coad i dac primul element este n L merg mai departe i apelez recursiv predicatul pentru restul listei i L . inclus_multimi(X,[Y]):- inclus(X,Y). inclus_multimi(X,[H|T]):- inclus(X,H), inclus_multimi(X,T). mpart lista de mulimi n cap i coad, coada ind restul de mulimi din list. Apelez funcia inclus pentru a vedea dac X este inclus n prima list din lista de mulimi, apelez recursiv inclus_multimi pentru a vedea dac X este inclus n restul de mulimi din list. Exemplul 0.6.9. Incrementai toate elementele unei liste. Programul se gsete implementat n ierul L7ex1.pl Apel: ?-increment (inc,[1,2,3],R). R=[2,3,4] Yes

Program: inc(X,Y):-Y is X+1. increment(F,[],[]). increment(F,[H|T],[R|RT]):- L=..[F,H,R],call(L),increment(F,T,RT). Programul folosete lista L pentru a aduna parametrii necesari pentru predicatul built-in call() care formeaz un nou scop, n cazul de fa apeleaz 80

incrementarea ecrui element. Apelul are ca parametri predicatul inc , cel care va incrementa elementele listei , lista i variabila care va ntoarce lista rezultat. Exemplul 0.6.10. Scriei un program care nlocuiete un element ntr-o list. Implementarea se gsete n ierul L7ex2.pl Apel: ?- subst(a,b,[b,b,c,[d,b]],R). R=[a,a,c,[d,b]] No Program: subst(N,V,[],[]):-!. subst(N,V,[V|T],[N|R]):-subst(N,V,T,R),!. subst(N,V,[X|T],[X|R]):-subst(N,V,T,R). Programul substituie un element la nivelul supercial al listei, observai c pentru lista [d,b] , b-ul din aceast list nu este nlocuit. Programul este structurat pe cazuri i anume , cazul n care din list poate extras elementul V ( cel ce va nlocuit ) i cazul n care se extrage din list un element oarecare. n primul caz se face cut pentru a nu se ncerca resatisfacerea predicatului subst pentru alte clauze, dac acest lucru s-ar ntmpla n lista R nu vom avea elementele substituite. Pe ntoarcere se reconstruiete lista ns n lista R ( rezultat ) vom avea lista modicat deoarece atunci cnd se poate extrage elementul V n R introducem elementul N (elementul cu care nlocuim V-ul). 81

Exemplul 0.6.11. Scriei un predicat care terge toate apariiile unui element ntr-o list (nivel supercial). Implementarea se gsete n ierul L7ex4.pl Apel: ?-sterge(a,[a,c,[a,b],a,f],R). R=[c,[a,b],f] Program: sterge(X,[],[]). sterge(X,[X|T],R):-sterge(X,T,R),!. sterge(X,[Y|T],[Y|R]):- sterge(X,T,R). Programul funcioneaz pe acelai principiu ca programul care nlocuiete elemente din list, ns de data aceasta n locul elementelor extrase nu se va aduga un alt element. Exemplul 0.6.12. Scriei un predicat care terge toate elementele dintr-o list dat care apar n alt list. Implementarea se gsete n ierul L7ex5.pl Apel: ?-stergere([1,2,3],[1,4,2,5,3,7],R). R=[4,5,7] Program: stergere([],L1,L1). stergere([H|T],L1,L3):-sterge(H,L1,R2),stergere(T,R2,L3). Predicatul ster-

gere/3 are nevoie ca nainte de a apelat s se ncarce ierul de la exemplul 82

precedent (consult(l4ex4).). Principiul de funcionare este foarte simplu, n antetul predicatului extragem un element din prima list pentru care apelm predicatul sterge/3 de mai sus. Elementul extras din prima list va ters din a doua list i predicatul stergere/3 se reapeleaz pentru coada primei liste lista R2 rezultat n urma tergerii i o list L3 care va lista ce va conine rezultatul nal. Exemplul 0.6.13. Scriei un predicat care insereaz un element naintea unui alt element al unei liste. Mai jos sunt prezentate dou variante de predicat ins/3 i ins2/3, primul predicat ins/3 insereaz pe X naintea lui A n lista L, numai la prima apariie a lui A, ins2/3 aeaz toate posibilitile de inserare, pentru o list care conine mai multe apariii ale lui A. Implementarea se gsete n ierul L7ex6.pl Apel: ?- ins(x,b,[d,b,c,b],L). L=[d,x,b,c,b] Program: ins(X,A,[],[]). ins(X,A,[A|T],[X,A|T]):- !. ins(X,A,[H|T],[H|R]):- ins(X,A,T,R). Apel: ?- ins2(x,c,[a,c,d],R). R=[a,x,c,d] ?- ins2(x,c,[a,c,d,c],R). 83

R=[a,x,c,d,c]; R=[a,c,d,x,c] Yes Program: ins2(X,A,L,R):- append(L1,[A|L2],L),append(L1,[X,A|L2],R). Exemplul 0.6.14. Implementai o serie de predicate care primesc ca parametru o list i care trebuie s simuleze o stiv FIFO, FILO, LIFO, LILO. Implementarea se gsete n ierul L7ex3.pl FIFO (First In First Out) - primul intrat , primul ieit. ?-pop([a,b,c],R). R=a ?-push(m,[a,b,c],R). R=[m,a,b,c] pop([H|T],H). push(X,L,[X|L]). FILO (First In Last Out) - primul intrat, ultimul ieit. ?-pop1([a,b,c],R). R=c ?-push1(m,[a,b,c],R). R=[m,a,b,c] pop1([X],X). pop1([H|T],R):-pop1(T,R). 84

push1(X,L,[X|L]). LIFO (Last In First Out) - ultimul intrat , primul iesit. ?-pop2([a,b,c],R). R=a ?-push2(m,[a,b,c],E). R=[a,b,c,m] pop2([H|T],H). push2(X,L,R):-append(L,[X],R). LILO (Last In Last Out) - ultimul intrat, ultimul ieit. ?-pop3([a,b,c],R). R=c ?-push3(m,[a,b,c],E). R=[a,b,c,m] pop3([X],X). pop3([H|T],R):-pop1(T,R). push3(X,L,R):-append(L,[X],R). Exemplul 0.6.15. Scriei un predicat care selecteaz dintr-o list numerele ntregi (numai de pe nivelul supercial al listei). Implementarea n ierul L8ex1.pl Apel: ?-select([1,a,3],R). R=[1,3] ?-select([1,[a,2],3],R). 85

R=[1,3] Program: select([],[]). select([H|T],[H|R]):-integer(H),select(T,R). select([H|T],R):-select(T,R). Programul funcioneaz asemntor unui if din programarea structurat. Scoate un element H din list i dac este ntreg l adug la lista rezultat i se reapelez , altfel dac interger(H) ntoarce fail atunci se ncearc satisfacerea celei de-a treia clauze, care scoate elementul din list. Ne oprim cnd lista va vid. Exemplul 0.6.16. Scriei un program care numr cte vocale sunt ntr-o list. Implementarea n ierul L8ex2.pl Apel: ?- nr_vocale([a,s],X). X=1 ?- nr_vocale([a,r,e,d,i],X). X=3 ?- nr_vocale([s,d],X). X=0 Program: member(X,[X|_]). member(X[_|T]):-member(X,T). 86

vocala(X):-member(X,[a,e,i,o,u]). nr_vocale([],0). nr_vocale([X|T],N):-vocala(X),nr_vocale(T,N1),N is N1+1,!. nr_vocale([X|T],N):-nr_vocale(T,N). nc un exemplu de predicat recursiv. Predicatul este structurat pe 2 cazuri simple, dac litera este sau nu vocal. Dac este, atunci se reapeleaz pentru restul listei i o variabil liber N1, care atunci cnd lista va vid va unicat cu 0, la revenirea din apeluri se vor numra vocalele. Dac litera nu este vocal predicatul se reaprelaz pentru restul listei. Cazul de baz este prima clauz a predicatului, care semnic faptul c n lista vid sunt 0 vocale. Exemplul 0.6.17. Selectai dintr-o list primele i ultimele N elemente. Implementarea se gsete n ierul L8ex3.pl Ultimul element dintr-o list: ?- ultimul([1,2,3,4],R). R=4 last(L,R):- append(X,[R],L). Primul element dintr-o list: ?- primul([1,2,3,4],R). R=1 primul(L,R):- append([R],X,L). Se observ modul n care predicatul-sistem append/3 rspunde interogrilor. Se poate construi foarte uor un predicat care s ntoarc primele i ultimele 87

N elemente. Apel: ?- prim([1,2,3,4,5,6],3,R). R = [1, 2, 3] Yes 4 ?- ultim([1,2,3,4,5,6],3,R). R = [4, 5, 6] Yes Program: ultim(L,N,R):- append(X,R,L),length(R,N). prim(L,N,R):- append(R,X,L),length(R,N). Predicatul sistem append/3 ind apelat cu primele variabile nelegate va ncerca toate posibilitile pentru care din R i X se obine lista L, aceea care va avea lungimea N va lista care ne intereseaz. Remarcai c lista rezultat R, se a pe poziii diferite n funcie de ecare apel append. Exemplul 0.6.18. Scriei un predicat care simuleaz o list circular. Implementarea se gsete n ierul L8ex4.pl Apel: ?- circular([a,b,c,d],R). R=[a,b,c,d] R=[b,c,d,a] R=[c,d,a,b] 88

R=[d,a,b,c] R=[d,a,b,c] Program: circ(_,[],_). circ([H|T],[_|Rest],R):- concat(T,[H],R),write(R),nl,circ(R,Rest,R1). circular(L,R):-circ(L,L,R). Lum lista [a,b,c,d] i punem primul element a la coad. Lista rezultat R (R=[b,c,d,a]) va intra din nou n bucl i din nou punem primul element la coad. Cnd tim s ne oprim? Introducem nc o variabil pe care o iniializm cu lista [a,b,c,d]. De ecare dat cnd obinem o lista circular nou scoatem din L=[_|Rest] un element i continum cu Rest. n momentul n care lista va vid ne oprim. Exemplul 0.6.19. Scriei un predicat care sorteaz cresctor o list de numere ntregi. Implementarea n ierul L8ex5.pl Apel: ?- sort_ins([13,2,6,1,5,9,7],R). R = [1, 2, 5, 6, 7, 9, 13] Yes Program: sort_ins(List,Sort):-i_sort(List,[],Sort). i_sort([],A,A). i_sort([H|T],A,Sort):-insert(H,A,NA),i_sort(T,NA,Sort). 89

insert(X,[Y|T],[Y|NT]):-X>Y,insert(X,T,NT). insert(X,[Y|T],[X,Y|T]):-X=<Y. insert(X,[],[X]). Exemplul 0.6.20. Scriei un predicat care permut o list folosind tergerea din list. Prezentm mai nti predicatele de tergere utilizate pentru a permuta lista. Implementarea n ierul L8ex6.pl Apel: ?-sterge(a,[a,c,[a,b],f],R). R=[c,[a,b],f] ?-sterge(X,[a,b,c],R). X=a R=[b,c] X=b R=[a,c] X=c R=[a,b] Predicat: sterge(X,[X|T],T). sterge(X,[Y|T],[Y|R]):-sterge(X,T,R). Predicatul de mai sus terge un element dintr-o list. Apel: ?-sterge_lista([1,2,3],[1,4,2,5,3,7],R). 90

R=[4,5,7]. Predicat sterge_lista([],L1,L1). sterge_lista([H|T],L1,L3):-sterge(H,L1,L2),sterge_lista(T,L2,L3). Predicatul de mai sus terge elementele unei liste dintr-o list, folosind tergerea unui singur element dintr-o list. ?-permutare([a,b,c],L). L = [[a, b, c], [a, c, b], [b, a, c], [b, c, a], [c, a, b], [c, b, a]] Predicat: permutare(L,R):- ndall(X,sterge_lista(X,L,[]),R). Predicatul sistem ndall/3 gsete toate soluiile predicatului sterge_lista/3 pe care le va returna n variabila R. Rezultatele intermediare vor obinute n variabila X. Exemplul 0.6.21. Scriei un predicat care aeaz toate permutrile unei liste folosind adugrile n list.(scoate pe rnd ecare element i l adaug n dreptul ecrui alt element). Implementarea n ierul L8ex7.pl Apel: ?- permutari([1,2],R). R=[[1,2],[2,1]] Predicate folosite: ?-adaug(a,[b,c,d],X). X=[a,b,c,d] 91

X=[b,a,c,d] X=[b,c,a,d] X=[b,c,d,a] ?-permut([a,b,c],X). X=[a,b,c] X=[b,a,c] X=[b,c,a] X=[a,c,b] X=[c,a,b] X=[c,b,a] Program: adaug(X,L,[X|L]). adaug(X,[L|H],[L|R]):-adaug(X,H,R). permut([],[]). permut([L|H],R):-permut(H,R1),adaug(L,R1,R). permutari(L,R):- ndall(P,permut(L,P),R). Exemplul 0.6.22. Scriei un predicat care gsete toate combinrile unei mulimi luate cte K. Implementarea n ierul L8ex8.pl Apel: ?- combinari([a,b,c],2,R). R=[[a,b],[a,c],[b,c]] ?- adauga(a,[[b],[c]],I). 92

I=[[a,b],[a,c]] Program: combinari(L,N,[L]):length(L,N),!. combinari(L,1,R):- pune_paranteze(L,R). combinari([H|T],K,R):K1 is K-1, combinari(T,K1,R1), adauga(H,R1,R2), combinari(T,K,R3), concat(R2,R3,R). adauga(X,[L],[[X|L]]). adauga(X,[H|T],[[X|H]|R]):-adauga(X,T,R). pune_paranteze([],[]). pune_paranteze([H|T],[[H]|R]):pune_paranteze(T,R). Exemplul 0.6.23. Scriei un predicat SWI-Prolog care "mpacheteaz" elemente consecutive identice dintr-o list. Implementarea n ierul L9ex1.pl Apel: ?- impacheteaza([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X). X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]] Program: 93

transfer(A, [], [], [A]). transfer(A, [B|C], [B|C], [A]) :A\=B. transfer(A, [A|B], C, [A|D]) :transfer(A, B, C, D). impacheteaza([], []). impacheteaza([A|B], [C|D]) :transfer(A, B, E, C), impacheteaza(E, D). Predicatul mpacheteaz elementele din lista B formnd o list, D, cu aceleai elemente ns coninute n subliste ale lui D. Predicatul transfer/4 este folosit pentru a scoate elementele identice din lista B i a depune rezultatul n lista D care va lista rezultat. La ncheierea acestei operaii predicatul impacheteaza/2 se reapeleaz pentru restul listei. Ne vom opri cnd ambele liste vor goale, lista procesat i lista rezultat, deoarece dac prima list a devenit vid i lista rezultat va vid, la revenirea din apeluri lista rezultat va conine sublistele cu elemente identice, care au fost introduse n antetul clauzei impacheteaza([A|B], [C|D]). Exemplul 0.6.24. Avnd programul de mai sus scriei un program care codic o list astfel: pentru termeni consecutivi , identici vom avea o list de liste de forma [[N,X],[M,Y]] unde N i M sunt numrul de apariii ale lui X, respectiv Y. Implementarea n ierul L9ex2.pl 94

Predicatul ensure_loaded(sier ) asigur faptul c ierul sier a fost ncrcat. El trebuie apelat nainte de a compila L9ex2.pl ?- ensure_loaded(L9ex1). Yes Apel: ?- codica[a,a,a,a,b,c,c,a,a,d,e,e,e,e],X). X = [[4,a],[1,b],[2,c],[2,a],[1,d][4,e]] Program: codica(L1,L2) :- impacheteaza(L1,L), transform(L,L2). transform([],[]). transform([[X|Xs]|Ys],[[N,X]|Zs]) :length([X|Xs],N), transform(Ys,Zs). Exemplul 0.6.25. Avnd exemplul de mai sus , scriei un predicat SWI-Prolog care decodic listele obinute cu programul din exemplul precedent. Implementarea n ierul L9ex3.pl Apel: ?- decodica([[4,a],[1,b],[2,c],[2,e]],R). R = [a, a, a, a, b, c, c, e, e] Program: decodica([],[]). decodica([X|Ys],[X|Zs]) :is_list(X), decodica(Ys,Zs). 95

decodica([[1,X]|Ys],[X|Zs]) :- decodica(Ys,Zs). decodica([[N,X]|Ys],[X|Zs]) :N > 1, N1 is N - 1, decodica([[N1,X]|Ys],Zs). Exemplul 0.6.26. Scriei un predicat care ntoarce o list L2 obinut din lista L1 prin adugarea la L2 a elementelor dintre indecii I i K. Implementarea n ierul L9ex4.pl Apel: trunc([a,b,c,d,e,f,g,h,i,k],3,7,L). L = [c,d,e,f,g] Program: trunc([X|_],1,1,[X]). trunc([X|Xs],1,K,[X|Ys]) :K > 1, K1 is K - 1, trunc(Xs,1,K1,Ys). trunc([_|Xs],I,K,Ys) :- I > 1, I1 is I - 1, K1 is K - 1, trunc(Xs,I1,K1,Ys). Exemplul 0.6.27. Scriei un predicat SWI-Prolog care terge toate elementele din N n N dintr-o list. Implementarea n ierul L9ex5.pl 96

Apel: ?- sterge([a,b,c,d,e,f,g,h,i,k],3,R). R = [a,b,d,e,g,h,k] Program: sterge([],_,[],_). sterge([_|Xs],N,Ys,1) :sterge(Xs,N,Ys,N). sterge([X|Xs],N,[X|Ys],K) :K > 1, K1 is K - 1, sterge(Xs,N,Ys,K1). Exemplul 0.6.28. Scriei un predicat SWI-Prolog care simuleaz o loterie. i anume se extrag N numere n din intervalul 1..M care vor introduse ntr-o list L. Implementarea n ierul L9ex5.pl Apel: ?- extrage(5,20,L). L = [2, 15, 4, 7, 9] n exemplul de mai sus N=5, M=20. Program: sterge(X,[X|Xs],1,Xs). sterge(X,[Y|Xs],K,[Y|Ys]) :K > 1, K1 is K - 1, sterge(X,Xs,K1,Ys). 97

select(_,0,[]). select(Xs,N,[X|Zs]) :- N > 0, length(Xs,L), I is random(L) + 1, sterge(X,Xs,I,Ys), N1 is N - 1, select(Ys,N1,Zs). interval(I,I,[I]). interval(I,K,[I|L]) :I < K, I1 is I + 1, interval(I1,K,L). extrage(N,M,L) :interval(1,M,R), select(R,N,L).

0.6.3

Exerciii propuse

Exerciiul 0.6.1. Scriei un predicat SWI-Prolog care simuleaz pe liste reuniunea, intersecia i diferena pentru mulimi. Exerciiul 0.6.2. Scriei un predicat SWI-Prolog care caut o list intr-o list de liste. Exerciiul 0.6.3. 98

Scriei un predicat SWI-Prolog care aeaz intersecia a dou liste care conin alte liste. Exerciiul 0.6.4. Scriei un program care aeaz reuniunea a dou liste de liste.

0.6.4

Teme de studiu

Tema 0.6.1. Rulai cu trace exemplele prezentate.

99

0.7
0.7.1
0.7.1.1

Grafuri. Arbori
Fundamente teoretice
Probleme de reprezentare

Reprezentarea datelor joac un rol important n programare, n general o form de reprezentare sau alta poate uura munca unui programator. De aceea ca mod de reprezentare a muchiilor unui graf alegem forma de mai jos a clauzelor, care credem c este cea mai potrivit pentru problemele prezentate n acest material. - muchie(A,B). - prin aceasta simbolizm faptul c exist muchie de la A la B. Reprezentarea de mai sus este sucient pentru grafurile orientate. Dac se dorete adugarea de costuri pentru muchii aceasta se poate face prin adugarea la predicatul muchie a unei variabile care s reprezinte costul traversrii muchiei de la A la B. Dorim n continuare pentru grafurile neorientate s avem un predicat care s reprezinte faptul c muchiile sunt neorientate sau c se poate circula n ambele sensuri. Pentru aceasta am putea adopta o construcie de forma: - muchie(A,B):- muchie(B,A). n felul acesta programul va intra ntr-un ciclu innit. O soluie la problem ar putea crearea de fapte de tipul muchie(a,b). i muchie(b,a). ns n felul acesta dublm numrul predicatelor, iar pentru un graf de dimensiuni considerabile efortul tastarii programului este prea mare (aceast abordare poate o soluie pentru reprezentarea grafurilor orientate). 100

Vom folosi predicatul urmtor pentru rezolvarea acestei probleme. legatura(X,Y) :- muchie(X,Y) ; muchie(Y,X). Semnul ";" reprezint o disjuncie ( sau logic ). Predicatul de mai sus ar putut scris i sub forma:

legatura(X,Y):- muchie(X,Y). legatura(X,Y):- muchie(Y,X).

Pentru reprezentarea arborilor vom folosi acelai predicat muchie(a,b). i legatura(X,Y).

0.7.2

Exemple

Exemplul 0.7.1. Considerm graful de mai jos, scriei un program SWI-Prolog care gsete toate drumurile ntre oricare 2 vrfuri ale grafului. Implementarea n ierul L10ex1.pl.

101

Apel: drum(1,5,R). R = [1, 3, 5] ; R = [1, 3, 6, 5] ; R = [1, 3, 2, 8, 4, 5] ; R = [1, 7, 5] ; R = [1, 6, 5] ; R = [1, 6, 3, 5] ; R = [1, 6, 3, 2, 8, 4, 5] ; No Program: muchie(1,3). muchie(1,7). muchie(1,6). muchie(2,3). muchie(2,8). muchie(3,5). muchie(3,6). muchie(4,5). muchie(4,8). muchie(5,6). muchie(5,7). legatura(X,Y) :muchie(X,Y) ; muchie(Y,X). drum(A,B,Drum) :mergi(A,B,[A],L), reverse(L,Drum). mergi(A,B,P,[B|P]) :legatura(A,B).

102

mergi(A,B,V,Drum) :legatura(A,C), C \== B, not(member(C,V)), mergi(C,B,[C|V],Drum). Exemplul 0.7.2. Avnd programul de mai sus scriei un predicat SWI-Prolog care gsete un drum nchis plecnd dintr-un vrf dat. Programul trebuie s returneze toate drumurile prin backtracking. Implementarea n ierul L10ex2.pl Apel: ?- ciclu(1,Drum). Drum = [1, 7, 5, 3, 1] ; Drum = [1, 7, 5, 6, 3, 1] ; Drum = [1, 7, 5, 4, 8, 2, 3, 1] ; ... Program: ciclu(A,P) :legatura(B,A), drum(A,B,P1), length(P1,L), L > 2, append(P1,[A],P). Exemplul 0.7.3. 103

Avnd graful de mai sus i reprezentarea lui n SWI-Prolog scriei un predicat care calculeaz gradul unui nod. Implementarea n ierul L10ex3.pl Apel: ?- grad(1,R). R=3 Yes Predicat: grad(Nod,R):- ndall(X,muchie(Nod,X),L),length(L,R). Pentru acest predicat folosim reprezentarea grafului din gura de mai sus i predicatele built-in ndall/3 i length/2 . Predicatul ndall/3 va gsi toate muchiile care exist de la Nod la X si va ntoarce n lista L veciniii lui Nod. Predicatul length/2 returneaz lungimea unei liste n cel de-al doilea parametru care trebuie s e o variabil liber la apel, dac este o variabil legat i primul parametru este liber atunci va crea o list aleatoare cu numr egal de elemente cu valoarea celuilalt parametru. Exemplul 0.7.4. Scriei un predicat SWI-Prolog care ntoarce ntr-o list toate nodurile unui graf i lungimea listei. Implementarea n ierul L10ex3.pl Apel: varfuri(R,N). R = [1, 2, 3, 4, 5, 6, 7, 8] N=8 Yes 104

Predicat: varfuri(R,N):ndall(X,(muchie(X,_); muchie(_,X)),L), sort(L,R),length(R,N). Predicatul built-in sort/2, dup cum i spune i numele, sorteaz lista L i ntoarce rezultatul n variabila R.

0.7.3

Exerciii propuse

Exerciiul 0.7.1. Modicai primul program prezentat (drum n graf) pentru a aa uxul maxim dintre 2 noduri (A i B) ale grafului. Fluxul maxim este valoarea minim a muchiilor grafului pe care le parcurgem pentru a ajunge din punctul A n B.

0.7.4

Teme de studiu

Tema 0.7.1. Scriei un program SWI-Prolog care parcurge un arbore.

105

0.8
0.8.1

Probleme speciale
Problema Damelor

Aceasta este o problem clasic n programarea calculatoarelor, dup cum se tie trebuie s plasm pe o tabl de ah, de dimensiune NN, N dame astfel nct s nu se atace reciproc. Dou dame se atac atunci cnd se gsesc pe aceeai linie, coloan sau diagonal. Reprezentm poziia celor N dame printr-o list de dimensiune N astfel : dac avem lista [4,2,7,3,6,8,5,1] aceasta nseamn c dama de pe coloana 1 se gsete pe linia 4, dama de pe coloana 2 se gsete pe linia 2 , .a.m.d. . Folosind acest mod de reprezentare a informaiilor i folosind permutri ale numerelor ntre 1 i N ne asigurm c oricare 2 dame nu se vor gsi pe aceeai linie sau coloan. Singurul test care ne mai rmne este testul diagonalelor, astfel o dam plasat pe coloana X i rndul Y ocup dou diagonale notate prin C (diagonala secundar) i D (diagonala principal) acestea vor un numr C=X-Y i D= X+Y , aceste valori , ale diagonalelor deja ocupate vor reinute n dou liste Cs i Ds. Apel: ?- dame_1(4,R). R = [2, 4, 1, 3] ; R = [3, 1, 4, 2] ; ?- dame_1(8,R). R = [1, 5, 8, 6, 3, 7, 2, 4] ; 106

R = [1, 6, 8, 3, 7, 4, 2, 5] ; R = [1, 7, 4, 6, 8, 2, 5, 3] ; R = [1, 7, 5, 8, 2, 4, 6, 3] ; ... Program: Predicatul dame_1(N,Qs) :- Qs este o soluie de aezare a celor N dame. dame_1(N,Qs) :- intre(1,N,Rs), permuta(Rs,Qs), test(Qs). Predicatul intre(A,B,L) :- L este o list de numere ntre A i B. intre(A,A,[A]). intre(A,B,[A|L]) :- A < B, A1 is A+1, intre(A1,B,L).

Predicatul permuta(Xs,Zs) :- lista Zs este o permutare a listei Xs. permuta([],[]). permuta(Qs,[Y|Ys]) :- del(Y,Qs,Rs), permuta(Rs,Ys). del(X,[X|Xs],Xs). del(X,[Y|Ys],[Y|Zs]) :- del(X,Ys,Zs).

Predicatul test(Qs) :- Lista Qs reprezint o soluie a damelor care nu se atac reciproc. test(Qs) :- test(Qs,1,[],[]).

Predicatul test(Qs,X,Cs,Ds) :- Damele din Qs, reprezentnd coloanele de la X la N, nu sunt n conict cu diagonalele Cs i Ds.

107

test([],_,_,_). test([Y|Ys],X,Cs,Ds) :C is X-Y, not(memberchk(C,Cs)), D is X+Y, not(memberchk(D,Ds)), X1 is X + 1, test(Ys,X1,[C|Cs],[D|Ds]). Iat o a doua versine n care permutarea este vericat nainte de a trece mai departe . dame_2(N,Qs) :intre(1,N,Rs), permuta_test(Rs,Qs,1,[],[]). permuta_test([],[],_,_,_). permuta_test(Qs,[Y|Ys],X,Cs,Ds) :del(Y,Qs,Rs), C is X-Y, not(member(C,Cs)), D is X+Y, not(member(D,Ds)), X1 is X+1, permuta_test(Rs,Ys,X1,[C|Cs],[D|Ds]). Programul se gsete implementat n ierul L11ex1.pl

0.8.2

Problema mutrii calului

Se d o tabl de sah de dimensiuni NN, se cere s se mute un cal pe tabl n asa fel nct la nal calul s trecut prin toate ptratele tablei. 108

Predicatul cal(N,Cal) :- Cal este o list ce conine rezultatul problemei sub elemente de forma linie/coloan reprezentnd poziiile pe care se poate muta calul. cal(N,Cal) :- M is N*N-1,cal(N,M,[1/1],Cal),write(Cal). Predicatul drum_inchis/2 calculeaz dac exist un drum nchis, i anume calul trebuie s se ntoarc n acelai ptrat din care a pornit. drum_inchis(N,Cal) :cal(N,Cal), Cal = [X/Y|_], sare(N,X/Y,1/1). cal(_,0,Cal,Cal). cal(N,M,Visited,Cal) :Visited = [X/Y|_], sare(N,X/Y,U/V), not(memberchk(U/V,Visited)), M1 is M-1, cal(N,M1,[U/V|Visited],Cal). Predicatul sare/3 specic modul n care calul poate sri pe tabl de la ptratul A/B la C/D. sare(N,A/B,C/D) :sare_dist(X,Y), C is A+X, C > 0, C =< N, D is B+Y, D > 0, D =< N.

109

Baza de cunotine cu distanele pe care le poate sri calul. sare_dist(1,2). sare_dist(2,1). sare_dist(2,-1). sare_dist(1,-2). sare_dist(-1,-2). sare_dist(-2,-1). sare_dist(-2,1). sare_dist(-1,2). Apel: ?- cal(5,R). Cal=[1/5, 3/4, 5/5, 4/3, 5/1, 3/2, 1/3, 2/5, 4/4, 5/2, 3/1, 1/2, 2/4, 4/5, 5/3, 4/1, 2/2, 1/4, 3/3, 2/1, 4/2, 5/4, 3/5, 2/3, 1/1]

0.8.3

Exerciii propuse

Exerciiul 0.8.1. O rm de cartograe urmrete s coloreze o hart a N tri cu M culori n aa fel nct dou ri vecine s nu e colorate cu aceeai culoare. Scriei un program Prolog care s aeze toate soluiile posibile pentru N i M date.

0.8.4

Teme de studiu

Tema 0.8.1. 110

Rulai programele prezentate folosind comanda trace.

111

0.9
0.9.1
0.9.1.1

Fiiere. Baze de date dinamice


Fundamente teoretice
Fiiere

SWI-Prolog dispune de 2 modaliti de lucru cu iere: Stilul Edinburgh care presupune gestionarea unui stream implicit, predicatele refer n mod implicit stream-ul curent, i stilul ISO Input and Output Streams, n care stream-urile sunt explicite si sunt create cu predicatul open/3 sau open/4. Fiecare stream astfel creat are un identicator unic folosit de alte predicate pentru a citi sau scrie pe streamul respectiv. Prezentm n continuare stilul Edinburgh. n acest stil, stream-ul este conectat n mod implicit la terminal ( monitor + tastatur pentru ieiri respectiv intrri), el poate schimbat cu predicatele: - see(+SrcDest) Deschide SrcDest pentru citire i l face stream-ul curent de intrare. - tell(+SrcDest) Deschide SrcDest pentru scriere i l face s e stream-ul curent de ieire. - append(+File) Similar cu tell/1, dar poziioneaz pointerul de scriere la nalul ierului. - seeing(?SrcDest) i telling(?SrcDest) nu returneaz numele ierului deschis pentru citire/scriere ci returneaz indenticatorul de stream. - seen i told nchid stream-ul curent. SrcDest poate un ier, terminalul sau un termen desemnat prin 112

pipe(Comanda). Iat cteva exemple pentru SrcDest: ?- see(f.txt). % citete din ierul f.txt ?- tell(user). % Scrie pe terminal. ?- tell(pipe(lpr)). % Scrie la imprimant n exemplul de mai sus user i lpr sunt cuvinte rezervate n SWI-Prolog. Stilul ISO Input and Output Streams presupune crearea stream-urilor prin intermediul predicatului open/3 sau open/4. Identicatorul de stream rezultat este apoi transmis predicatelor care fac citiri i scrieri pentru a specica sursa sau destinaia datelor. Predicatele built-in care respect acest stil/standard sunt: open(+SrcDest, +Mode, -Stream, +Options) SrcDest specic una din opiunile de mai sus, Mode poate read, write, append sau update, Stream poate e o variabil care la nal va conine identicatorul de stream e un atom i n cazul acesta atomul va identicatorul de stream. Options pate : - type(Type) se folosete pentru a putea scrie n mod text n mod compatibil cu sistemul de operare. Dac se folosete tipul binar octeii vor scrii fr a tradui. De menionat c pe sistemele Unix nu se face diferen ntre modul text i binar. - alias(Atom) d unui stream un nume. Atenie la aceast opiune deoarece numele de stream-uri sunt globale. Exemplu: ?- open(data, read, Fd, [alias(input)]). , ...,read(input, Term),... - eof_action(Action) denete ce se ntampl n momentul n care se ajunge

113

la nal de ier. - buer(Buering) deneste posibilitatea de a avea un buer. - close_on_abort(Bool) nchide stream-ul dac n timpul execuiei programului se apeleaz predicatul abort/0. - lock(LockingMode) ncearc s blocheze ierul pentru ca alte procese s nu l modice n timpul executiei programului. n mod implicit ierul nu va blocat , ns locking mode poate read sau shared, adic alte procese(programe) pot accesa ierul numai pentru citire. open(+SrcDest, +Mode, ?Stream) este echivalent cu open/4 cu lista de opiuni vid. open_null_stream(?Stream) deschide un stream vid. Toate funciile sunt active pentru un asemenea stream, dar o ncercare de a citi de pe un astfel de stream returneaz end_of_le. close(+Stream) nchide stream-ul specicat. Dac acest stream este streamul curent pentru intrare/ieire atunci terminalul este fcut stream curent pentru intrare/ieire. set_stream(+Stream, +Attribute) seteaz stream-ului atributele prezentate mai sus la predicatul open.

0.9.1.2

Baze de date dinamice.

Un program este o baz de date deoarece programul ofer posibilitatea interogrii "bazei de date" compus din fapte i reguli. O astfel de baz de date se numete "static" deoarece ea nu poate modicat n timpul execuiei pro114

gramului. n SWI-Prolog exist posibilitatea de a crea baze de date dinamice, acestea se refer la faptul c la un moment dat putem avea o baz de fapte creat n timpul execuiei programului. Spre exemplu n timpul executiei programului dorim s mai adugm la baza de fapte nc o clauz. SWI-Prolog pune la dispoziie urmtoarele predicate-sistem pentru lucrul cu baze de date dinamice: - assert(+Term) adaug un fapt la baza de date ca ultim fapt sau clauz a predicatului corespunztor. - asserta(+Term) echivalent cu predicatul de mai sus, dar Term este adugat ca prim clauz sau fapt al unui predicat. - assertz(+Clause) echivalent cu assert/1 . - retract(+Term) atunci cnd Term este atom sau termen el este unicat cu primul fapt sau prima clauz din baza de date , iar faptul sau clauza este ters din baza de date. - retractall(+Head) toate fapte sau clauzele cu care Head se poate unica sunt terse din baza de date. - abolish(+PredSpec) terge toate predicatele specicate de PredSpec, unde PredSpec este de forma Predicat/Aritate. Tot ce are legtura cu predicatul specicat este ters din sistem.

0.9.2

Exemple

Exemplul 0.9.1. Scriei un program care citete litere dintr-un ier(litere.txt), le separ n 115

vocale i consoane, apoi le scrie n iere diferite (vocale.txt i consoane.txt). Implementarea n ierul L12ex1.pl(Atenie la formatul ierului! Literele sunt scrise pe cte un rnd urmate de "." doarece SWI-Prolog le consider fapte.) Apel: ?- start. Yes Program: vocala(a). vocala(e). vocala(i). vocala(o). vocala(u). citeste(L):read(X), X \= end_of_le, append(L,[X],Rez), citeste(Rez). citeste(L):separ(L,Vocale,Consoane), vocale(Vocale), consoane(Consoane). separ([],[],[]). separ([Litera|R],[Litera|Cons],Voc):-

116

not(vocala(Litera)), separ(R,Cons,Voc). separ([Litera|R],Cons,[Litera|T]):vocala(Litera), separ(R,Cons,T). vocale(V):tell(vocale.txt),scrie(V),told. consoane(C):tell(consoane.txt),scrie(C),told. scrie([]). scrie([C|Rest]):write(C),scrie(Rest). start:see(litere.txt),citeste([]),seen. Programul se ruleaz apelnd start. i nu va avea nici un output pe consol deoarece prelucreaz ierul litere.txt , iar rezultatul va scris sub form de iere n directorul curent n ierele vocale.txt i consoane.txt . Predicatul citeste/1 citete din ierul litere.txt i dac nu s-a ajuns la nalul ierului adaug la o list, dac se ajunge la nal cnd se va face Redo din clauza secund a predicatului citeste/1 se va procesa lista i vor scrise ierele cu vocale i consoane. Exemplul 0.9.2. Scriei un program SWI-Prolog care introduce ntr-o baz de date dinamic 117

predicate de forma divizor(X,Y) i par(X) , unde divizor este un predicat care semnic faptul c Y este divizorul lui X, iar par(X) semnic faptul c X este un numr par. Implementarea n ierul L12ex2.pl Apel: ?- apel. Continuati?(da/nu)d. X=4. Y=2. Continuati?(da/nu)d. X=8. Y=4. Continuati?(da/nu)d. X=10. Y=5. Continuati?(da/nu)n. Yes ?- listing(are). :- dynamic are/2. are(2, 1). are(2, 1). are(4, 2). are(4, 2). are(8, 4). are(10, 5).

118

Yes ?- listing(par). :- dynamic par/1. par(2). par(2). par(4). par(4). par(8). Yes ?Program: start:write(X=),read(X), write(Y=),read(Y), M is X mod Y,M=0, adauga(X,Y),go. adauga(X,Y):- assertz(are(X,Y)),fail. adauga(X,Y):- par(Y),assertz(par(X)). adauga(_,_). go:write(Continuati?(da/nu)),read(R), R=d,start. % go:- retract(are(_,_)),fail.

119

% go:- retract(par(_)),fail. go. apel:- asserta(par(2)),go. Programul funcioneaz pe principiul: dac Y divide pe X i Y este numr par atunci X este numr par. Liniile 6 i 7 din program sunt comentate deoarece nu vrem ca programul s tearg predicatele adugate n baza de date dinamic, n cazul n care nu se continu introducerea de numere. Pentru a urmri ns modul n care funcioneaz predicatul retract ele trebuiesc decomentate.

0.9.3

Exerciii propuse

Exerciiul 0.9.1. Scriei un program Prolog care citete de la tastatur informaii de forma persoana(nume(NumePrenume),telefon(NrTel)). le introduce n baza de date dinamic i le salveaz ntr-un ier specicat de utilizator, care mai apoi poate citit i ncrcat n baza de date dinamic.

Exerciiul 0.9.2. Modicai programul de mai sus referitor la baze de date dinamice astfel nct s nu se adauge de mai multe ori acelai fapt n baza de date. 120

0.9.4

Teme de studiu

Tema 0.9.1. Rulai programele prezentate ca exemple, folosind comanda trace.

121

122

Capitolul 1 Probleme de la concursurile de programare

123

1.1
1.1.1

Probleme de la concursurile de programare


Ascii

Pentru un N dat scriei un predicat cross/1 unde cross(N) deseneaz gura de mai jos. n stnga este gura corespunztoare penru N=5, sgeile indicnd dimensiunile , iar n dreapta este gura corespunztoare pentru N=3. Programul trebuie s funcioneze pentru orice numr impar ntre 3 i 23. Adugarea de spaii n faa celui mai din stnga asterix nu este permis.

Figura 1.1: Exemple de apel pentru N=5 i respectiv N=3

(The 10th Prolog Programming Contest - 20th International Conference on Logic Programming, ICLP 2004, Saint-Malo, Frana) 124

1.1.2

Staii

Belgia este o ar a cilor ferate. n 5 mai 1835 primul tren din Europa conecta capitala Bruxelles de oraul Mechelen. n scurt timp au aprut mult mai multe linii ferate , nscndu-se astfel o reea feroviar dens. Totui trenurile ntrzie i nu se poate face nimic pentru a preveni acest lucru. ns orice belgian poate locui n orice parte a rii i poate cltori cu trenul pn la serviciu fr s piard prea mult timp pe drum. i cum nu deprtarea fa de locul de munc sau de staiile mijloacelor de transport n comun nu este o problem , alte lucruri stau la baza alegerii unui loc pentru a locui . Scriei un predicat statie/1 care returneaz staia ( deci i oraul ) unde este bine s locuiasc un belgian. Predicatul trebuie s ntoarc un ora sau fail n cazul n care un astfel de ora nu exist. Un ora n care este bine s locuieti este un ora care nu este mare. Un ora mare este acela care are mai mult de 2 legturi directe cu mai mult de 2 alte orae. n plus un ora mic n care este bine s locuieti se a la fel de aproape de alte 2 orae mari. Informaiile despre legturile ntre orae sunt reprezentate ca fapte cale/2. Toate cile ferate sunt bidirecionale i la fel de lungi. Rspunsul nu trebuie s conin fapte. Iat exemple de rspunsuri : cale(bruxel,mechelen). cale(bruxel, antwerpen). cale(bruxel,gent). cale(antwerp,mechelen). 125

cale(antwerp,gent). cale(gent,brugge) ?- statie(X). X=mechelen

cale(bruxel,charleroi). cale(bruxel,haacht). cale(haacht,mechelen). cale(mechelem,berchem). cale(berchem,antwerp). cale(bruxel,boom). cale(boom,antwerp). cale(antwerp,eindhoven). ?-statie(X). X=boom (The 10th Prolog Programming Contest - 20th International Conference on Logic Programming, ICLP 2004, Saint-Malo, Frana)

1.1.3

Triplete

S se genereze toate tripletele (X,Z,Y) care sunt numere ntregi din intervalul [0,9] i (10*X+Y)/(10*Y+Z)=X/Z. Datele de ieire trebuie s e sub forma urmtoare: 359 126

316 Dac (3,5,9) i (3,1,6) sunt soluii. (Prolog Programming Contest - 14 Noiembrie 1994 , Ithaca, ILPS94)

1.1.4

Spirala

Se dau a i b dou numere ntregi pozitive, se cere s se aeze pe ecran un dreptunghi cu lungimea b i limea a care conine numerele de la 1 la a*b aezate n spiral. Pentru a=4 i b=3 rezultatul este urmtorul: 1 10 9 2 11 12 3 4 5

8 7 6 Coloanele trebuie aliniate la dreapta i trebuie s ocupe N+1 poziii, unde N este numrul cifrelor reprezentrii zecimale a lui a*b. (Prolog Programming Contest - 14 Noiembrie 1994 , Ithaca, ILPS94)

1.1.5

Perioada

Scriei un predicat perioada/3 care se apeleaz cu primii 2 parametri numere ntregi pozitive i cel de-al treilea este o variabil liber. Un astfel de apel trebuie s unice cel de-al treilea parametru cu o list de ntregi (de la 0 la 9) care reprezint perioada obinut atunci cnd primul argument este mprit la argumentul secund. Exemple: ?- perioada(3,4,P). 127

P=[0] % deoarece 3/4 = 0,250000. . . ?- perioada(4,3,P). P=[3] % deoarece 4/3 = 1.33333. . . ?- perioada(1,7,P). P=[1,4,2,8,5,7] % deoarece 1/7 = 0.142857142857. . . n ultimul exemplu P=[2,8,5,7,1,4] este de asemenea , un rspuns corect, orice permutare a listei ind un rspuns corect. (Second Prolog Programming Contest - 4 Decembrie 1995 , Portland , Oregon ILPS95)

1.1.6

Numere

Se consider o gril innit care are un numr nit de puncte luminoase (a se vedea gura de mai jos). Aceste puncte luminoase sunt reprezentate de fapte de forma iluminat/4 i au un punct de start i un punct de nal ca argumente. Asemntor unui unui ceas electronic aceste puncte pot forma numere de la 0 la 9. Se cere s se scrie predicatul numere/1 care returneaz o list (fr duplicate, ordinea neind important) a tuturor numereleor care pot recunoscute dndu-se setul de fapte pentu punctele luminoase. Pentru gura 1 avem numerele: ?- numere(L). L=[0,1,2,3,4,5,6,7,8,9]

Figura 1 conine ntr-adevr toate numerele de la 0 la 9. Pentru a ntelege cum 128

Figura 1.2: Exemplu de display digital

este format un numr punctul din centru este considerat ca avnd coordonatele (0,0) , astfel numrul 3 poate reprezentat prin urmtorul set de fapte: iluminat(1,2,2,2). iluminat(2,2,2,3). iluminat(2,4,2,3). iluminat(2,3,1,3). iluminat(2,4,1,4). Nu este permis scalarea numerelor , de exemplu numrul 8 din gura 2 nu trebuie recunoscut. Pe de alt parte ns numerele pot rotite si/sau pri care pot recunoscute din conguraia unor puncte luminoase. Spre exemplu se consider gura 3 : ?- numere(L). L=[1,3,4,7] Orientarea numerelor nu este aceeai n toate cazurile, iar un punct luminos poate folosit ca parte component pentru mai multe numere (de exemplu numrul 9 poate ascunde numrul 4 i numrul 1, el nsui poate considerat un 6 rotit). (Second Prolog Programming Contest - 4 Decembrie 1995 , Portland , Oregon ILPS95) 129

1.1.7

Triunghi

Un triunghi de mrimea 5 arat pe ecran n felul urmtor:

Remarcai faptul c exist un spaiu ntre ecare stelu de pe un rnd orizontal. ntre vrful unui triunghi de dimensiune N i partea stng a ecranului nu trebuie s e mai mult de N+2 spaii. Scriei predicatul triunghi/1 care este apelat cu un ntreg mai mare dect 0 i care deseneaz triunghiul de dimensiunea respectiv pe ecran. (Second Prolog Programming Contest - 4 Decembrie 1995 , Portland , Oregon ILPS95)

1.1.8

Diamant

Desenai pe ecran un diamant de forma prezentat mai jos. Generalizai din exemple. Predicatul diamant/1 va trebui apelat cu un ntreg mai mare dect 0, reprezentnd dimensiunea diamantului. Iat exemple de apel ale acestui predicat: ?- diamant(2). 130

1 3 2

4 ?-diamant(3). 1 4 7 8 5 6 2 3

9 ?-diamant(8).

(Second Prolog Programming Contest - 4 Decembrie 1995 , Portland , Oregon ILPS95)

1.1.9

Drum

Se consider o tabl ptratic de dimensiune N (considerm N=4 n acest exemplu, acest lucru este dat n program de faptul dimensiune(4)), exist un punct de nceput (ntotdeauna ptratul cu coordonatele 1,1) i un punct de nal 131

(dat n program de faptul mergi(1,4,f)). Exist un drum corect ntre punctul de nceput i punctul de sfrit, acest drum este marcat , ecare ptrat coninnd informaii despre cum se ajunge la urmtorul ptrat , sub forma unui fapt: mergi(1,1,u). % de la 1,1 mergi n sus , adic spre 1,2 mergi(1,2,u). mergi(1,3,r). % de la 1,3 mergi la dreapta , adica spre 2,3 mergi(2,3,r). mergi(3,3,d). % de la 3,3 mergi n jos , adic spre 3,2 mergi(3,2,d) mergi(3,1,r) Dac am avut un l acesta ar nsemnat la stnga , desigur f nseamn destinaia nal. Informaia de mai sus reprezint tabla urmtoare:

Figura 1.3: Tabla nemodicat de spiritul ru

Pe o astfel de tabl nu este desigur dicil s se gseasc drumul de la 1,1 la 1,4, ns un spirit ru a ters unele informaii de pe tabl i fapte de forma mergi/3 astfel nct drumul nu mai are o reprezentare complet. Totui nu a fost sucent de ru deoarece 2 ptrate vecine din drum nu au informaie lips , 132

punctul de nal de asemenea nu lipsete i cel mult 2 vecini ai ptratelor lips aparin drumului corect (ptratele n diagonal nu sunt considerate vecine) drumul i n acest caz este uor de gsit. Un al doilea spirit , mult mai ru dect primul a introdus informaii pentru ecare ptrat care NU se a pe drumul spre ptratul nal, informaiile sunt de aa natur nct dac sunt considerate corecte e se iese de pe tabl e formeaz un cerc . (n mod particular nu vor ntlnite ptrate goale).

Figura 1.4: Tabla alterat

Se cere s se scrie un predicat drum/1 care returneaz drumul corect sub forma unei liste ncepnd cu 1,1 i terminnd cu punctul nal , lista ind ordonat dea lungul drumului parcurs. Pentru exemplul de mai sus drum/1 d urmtorul rezultat: X=[(1,1),(1,2),(1,3),(2,3),(3,3),(3,2),(3,1),(4,1)] (Prolog Programming Contest - 14 Noiembrie 1994 , Ithaca ILPS94) 133

1.1.10

Tabla

Se d o tabl de dimensiune 4x4 i n ecare ptrat un operator binar i un operand numr ntreg, Se pornete cu 0 ca valoare curent i se alege un drum pe tabl astfel nct s se viziteze ecare ptrat o singur dat. De ecare dat se execut operaia avnd ca operand stng valoarea curent i continund cu rezultatul ca valoare curent. La nalul drumului, valoarea curent depinde de drumul ales, aceast valoare se numete valoarea drumului. Trebuie gsit valoarea maxim a tuturor drumurilor i numrul drumurilor care au aceast valoare. O astfel de tabl i reprezentarea corespunztoare ei se gsete n gura 1.5. Predicatul tabla/3 are ca prim argument tabla (datele de intrare) i produce

Figura 1.5: Exemplu de tabl i reprezentarea corespunztoare

ca argument secund valoarea maximal a drumurilor, argumentul numrul 3 ind numrul drumurilor care au aceast valoare maximal. 134

1.1.11

arpele belgian

arpele belgian este un animal care are pe corp un tipar, dar acest tipar nu se repet de un numr integral de ori. Un tipar este o secven de inele, iar un inel are un identicator care este un atom de lungime 1. De asemenea, arpele belgian este un animal cruia i place s stea ncolcit ntr-un fel anume: ntotdeauna se aseaz ntr-un dreptunghi cu capul n colul din stnga-sus al dreptunghiului i corpul ntinzndu-se pe ecare rnd. Se cere s se scrie un predicat sarpe/3 care s aeze un astfel de arpe belgian. Acel predicat va apelat cu urmtoarele trei argumente: - o list de atomi care reprezint tiparul care se a pe corpul arpelui. - o list a crei lungime este numrul de inele care acoper o linie din dreptunghiul n care st arpele (lista nu este vid) . - o list a crei lungime este numrul de inele care acoper o coloan din dreptunghiul n care st arpele (lista nu este vid). Predicatul trebuie s aib urmtorul rezultat pe ecran: ?- sarpe([a,b,c,d],[_,_,_,_,_],[_,_,_]). (arpele ntins arat astfel a b c d a b c d a b c d a b c) abcda badcb cdabc nainte de a ncepe implementarea acestui predicat trebuie tiut c arpele belgian dezaprob operatorii aritmetici, astfel soluia acestui predicat nu trebuie s conin nici un fel de operatori aritmetici. Folosirea urmtoarelor predicate 135

este interzis: is < > =< >= + - * name arg functor =.. (4th Annual Prolog Programming Contest 9 iulie 1997, Leuven)

1.1.12

Hexagon

Se consider un hexagon compus din hexagoane mai mici numerotate (vezi gura 1.6). Se cere s se genereze mulimea hexagoanelor mici aate la

distana N (cu N dat) fa de un hexagon H dat. Predicatul hex/4 are ca argumente dimensiunea S a hexagonului mare (adic numrul de hexagoane mici din prima coloan a hexagonului mare) , al doilea argument este H, numrul hexagonului mic, iar al treilea argument este distana N. Predicatul hex/4 trebuie s unice ce de-al patrulea argument cu lista tuturor numerelor hexagoanelor mici aate la distana N de hexagonul H. Lista trebuie s e sortat. Exemple de apel pentru predicatul hex/4: ?- hex(3,1,0,L). L=[3] ?- hex(3,1,1,L). L=[2,4,5] ?- hex(3,1,2,L). L= [3,6,8,9,10] ?- hex(3,1,3,L). L = [7,11,13,14,15] 136

?- hex(3,1,4,L). L = [12,16,17,18,19] ?- hex(3,1,5,L). L = [] (4th Annual Prolog Programming Contest 9 iulie 1997, Leuven)

Figura 1.6: Hexagon

137

138

Capitolul 2 Soluiile problemelor propuse


2.1 Introducere. Fapte. Reguli

Rezolvarea 2.1.1. Denii predicatele cumnat, matu, unchi, strabunic, soacr.

2.1.1

Soluie teoretic

Pentru a putea deni predicatele cerute de exerciiu avem nevoie de un arbore genealogic care se va traduce n PROLOG prin mai multe predicate de tipul fapt.Predicatul barbat(X) simbolizeaz faptul ca X este brbat , acest fapt ne va util n denirea celorlalte predicate. Predicate de forma casatorit(gicu,elena). se traduc n limbaj natural n faptul "gicu este cstorit cu elena", lucru valabil i n cazul predicatelor parinte/2 i frate/2. Dup ce am stabilit un arbore genealogic trecem la scrierea predicatelor de tip fapte, pentru 139

toate relaiile cerute avem nevoie de predicatele casatorit(A,B), parinte(A,B), frate(A,B), vom nlocui variabilele A i B cu numele persoanelor din arborele nostru genealogic. Pentru a arta c dac A este casatorit cu B i reciproca este adevrat folosim predicatul casatoriti(A,B):- casatorit(A,B);casatorit(B,A). unde semnul ";" are valoarea unui sau logic, folosim aceeai construcie pentru predicatele frati i parinti. Predicatul cumnat(X,Y) va gsi soluii dac se realizeaz frati(Y,Z) i casatoriti(X,Z) prin aceasta vrem s simbolizm faptul c X este cumnatul lui Y dac Y are o sor (adic Y cu Z sunt frai, iar Z nu este brbt) i sora lui Y este cstorit cu X. Predicatul unchi(A,B) se realizeaz dac A este barbat, C este printele lui B i C cu A sunt frai. Acest predicat mai are o posibilitate de a se realiza, aceasta dac D este printele lui B, D este frate cu C, C este csatorit cu A i A este brbat. Predicatul matusa are si el 2 posibiliti de a se realiza deoarece pentru matusa(A,B) avem posibilitatea ca A s e mtua lui B dac parinti(C,B) adic unul parintii lui B sunt C care poate frate cu A i binenteles A nu este brbat. Posibilitatea a doua A este cstorit cu C i B are printe D , C i D sunt frai i n plus A nu este brbat. Predicatul strabunic(A,B) folosim predicatul bunic(B,C) prezentat i adugm condiia C s e printe pentru B. Predicatul soacr are 3 conditii care trebuie ndeplinite soacra(M,N) dac N i Z sunt cstorii, M este printe pentru Z i binenteles Y nu este brbat. Codul surs al programului se gsete n ierul L1r1.pl .

140

2.1.2

Apel

Pentru cine este gicu cumnat? ?- cumnat(gicu,X). X = gigel Are gigel cumnat? ?- cumnat(X,gigel). X = gicu Cine este mtusa alinei? ?- matusa(X,alina). X = ioana ; X = anca ; Pentru cine este mtu elena? ?- matusa(elena,X). X = costi ; X = gabi ; X = catalin ; No Cine este unchiul lui costi? ?- unchi(X,costi). X = gicu ; X = gigel ; No Nepoii lui gicu sunt: 141

?- unchi(gicu,X). X = costi ; X = gabi ; X = catalin ; No Cine este soacra mariei? ?- soacra(X,maria). X = monica ; No maria este soacr pentru: ?- soacra(maria,X). X = gigel ; X = elena ; X = anca ; No Strbunicul alinei este X: strabunic(X,alina). X = marin ; No

2.1.3

Cod surs

barbat(marin). barbat(ion). barbat(gicu). 142

barbat(george). barbat(gigel). barbat(andrei). barbat(costi). barbat(gabi). barbat(catalin). casatorit(marin,monica). casatorit(ion,maria). casatorit(gicu,elena). casatorit(george,anca). casatorit(gigel,ioana). casatoriti(A,B):- casatorit(A,B);casatorit(B,A). parinte(marin,ion). parinte(monica,ion). parinte(ion,gicu). parinte(maria,gicu). parinte(ion,george). parinte(maria,george). parinte(ion,ioana). parinte(maria,ioana). parinte(gicu,andrei). parinte(elena,andrei). parinte(gicu,alina). parinte(elena,alina). parinte(george,costi). parinte(anca,costi). parinte(gigel,gabi). parinte(gigel,catalin). parinte(ioana,gabi). parinte(ioana,catalin). parinti(A,B):-parinte(A,B);parinte(B,A). frate(gicu,george). frate(gicu,ioana). frate(george,ioana). frate(andrei,alina). frate(gabi,catalin). frati(A,B):- frate(A,B);frate(B,A). soacra(M,N):-

143

casatoriti(N,Z),parinte(M,Z),not(barbat(M)). cumnat(X,Y):frati(X,Z),not(barbat(Z)),casatoriti(Z,Y). matusa(A,B):parinte(C,B),frati(C,A),not(barbat(A)). matusa(A,B):casatoriti(A,C),parinte(D,B),frati(C,D),not(barbat(A)). unchi(A,B):parinte(C,B),frati(C,A),barbat(A). unchi(A,B):parinte(D,B),frati(C,D),casatoriti(C,A),barbat(A). bunic(A,B):parinte(C,B),parinte(A,C). strabunic(A,B):bunic(A,C),parinte(C,B),barbat(A).

2.2

Termeni.

Variabile.

Backtracking.

Predicatele-sistem trace, read, write


Rezolvarea 2.2.1. Un om cumpar o main dac i place i dac poate s o ia. Unui om i place o main dac are puterea pe care i-o dorete. Un om poate s ia o main dac are destui bani n cont s o cumpere sau dac ind casatorit, 144

soiei i place i ei maina i au mpreun bani s o cumpere.

2.2.1

Soluie teoretic

Pentru a rezolva aceast problem denim predicate pentru diferite tipuri de maini: pret_masina(masina,pret) este predicatul care denete pretul unei maini, putere reprezint puterea unei maini, putere_minima(masina,putere) este puterea minim pe care i-o dorete un om de la o main. Denim de asemenea i fapte pentru suma pe care o are un om n cont i pentru faptul de a cstorit sau nu. Avem apoi predicatul place(X,Y) i vrem s simbolizm faptul c lui X i place maina Y dac are puterea T i puterea_minim nu este mai mic dect T. X va putea cumpra maina Y dac are n cont T i T este mai mare dect T1, preul mainii. Exist i o a doua posibilitate de a cumpra maina i pentru aceasta redenim (adugm nc o clauz) predicatul poate astfel dac sotul lui X este R i R place maina Y i sumele adunate din conturile lor sunt mai mari dect T, pretul mainii, atunci vor cumpra maina. Ne mai rmne s apelm predicatele de mai sus ntr-un predicat general cumpara(X,Y) dac i place i dac poate.

2.2.2

Apel

?- cumpara(ion,ferrari). No 23 ?- cumpara(gicu,ferrari). Yes 145

2.2.3

Cod surs

Codul surs al programului de mai jos se gsete n ierul L2r1.pl pret_masina(ferrari,15000). pret_masina(mazda,12000). pret_masina(skoda,1100). pret_masina(dacia,350). putere(ferrari,500). putere(dacia,65). putere(mazda,350). putere(skoda,75). cont(ion,11000). cont(gicu,13000). cont(nicu,7000). cont(ana,5000). cont(anda,10000). putere_minima(ion,150). putere_minima(gicu,300). putere_minima(nicu,500). putere_minima(ana,300). putere_minima(anda,350). sot(gicu,ana). sot(nicu,anda). place(X,Y):-putere(Y,T),putere_minima(X,T1),T>=T1. 146

poate(X,Y):-cont(X,T),pret_masina(Y,T1),T>=T1. poate(X,Y):-sot(X,R),place(R,Y),cont(X,T1),cont(R,T2), pret_masina(Y,T),TT=T1+T2,TT>=T. cumpara(X,Y):-place(X,Y),poate(X,Y).

Prezentm n continuare modul n care functioneaz trace pentru un apel particular al predicatului cumpara/2: ?- trace,cumpara(gicu,ferrari). <- linia de comanda Call: (9) cumpara(gicu, ferrari) ? creep <- apelul predicatului cumpara Call: (10) place(gicu, ferrari) ? creep <- predicatul cumpara se satisface dac lui gicu i place maina ( are puterea dorit ) i poate s o cumpere Call: (11) putere(ferrari, _L194) ? creep <- se apeleaz predicatul putere Exit: (11) putere(ferrari, 500) ? creep <- puterea mainii este 500 Call: (11) put_min(gicu, _L195) ? creep <- se apeleaz put_min Exit: (11) put_min(gicu, 300) ? creep <- puterea minim dorit de gicu este 300 ^Call: (11) 500>=300 ? creep <- se compar puterea mainii cu puterea minim dorit ^Exit: (11) 500>=300 ? creep <- relaia putere main >= putere dorit este adevrat Exit: (10) place(gicu, ferrari) ? place(gicu,ferrari) Call: (10) poate(gicu, ferrari) ? creep <- mai trebuie ndeplinit condiia po147 creep <- se iese cu succes din apelul

sibilitii nanciare, se apeleaz poate(gicu,ferrari). Call: (11) cont(gicu, _L194) ? creep Exit: (11) cont(gicu, 13000) ? creep <- n contul lui gicu se gsesc 13000 uniti Call: (11) car_cost(ferrari, _L195) ? creep Exit: (11) car_cost(ferrari, 15000) ? creep <- maina cost 15000 uniti ^Call: (11) 13000>=15000 ? creep ^Fail: (11) 13000>=15000 ? creep <- predicatul aritmetic >= nu se ndeplinete deoarece gicu nu are suciente uniti pentru a cumpra maina singur Redo: (10) poate(gicu, ferrari) ? creep <- se ncearc resatisfacerea predicatului poate(gicu,ferrari) pentru cea de-a doua clauz Call: (11) sot(gicu, _L194) ? creep <- pentru a se ndeplini poate pentru a doua clauz trebuie ndeplinite sot, place, putere, putere_min Exit: (11) sot(gicu, ana) ? creep <- gicu are soie pe ana Call: (11) place(ana, ferrari) ? creep <- anei i place ferrari ? Call: (12) putere(ferrari, _L209) ? creep Exit: (12) putere(ferrari, 500) ? creep Call: (12) put_min(ana, _L210) ? creep Exit: (12) put_min(ana, 300) ? creep <- puterea minim pe care i-o dorete ana de la main este 300 ^Call: (12) 500>=300 ? creep ^Exit: (12) 500>=300 ? creep Exit: (11) place(ana, ferrari) ? creep <- anei i place ferrari

148

Call: (11) cont(gicu, _L195) ? creep Exit: (11) cont(gicu, 13000) ? creep <- gicu are n cont 13000 uniti Call: (11) cont(ana, _L196) ? creep Exit: (11) cont(ana, 5000) ? creep <- ana are n cont 5000 uniti Call: (11) car_cost(ferrari, _L197) ? creep Exit: (11) car_cost(ferrari, 15000) ? creep <- maina cost 15000 uniti ^Call: (11) _L198 is 13000+5000 ? creep ^Exit: (11) 18000 is 13000+5000 ? creep <- gicu i ana au mpreun 18000 uniti ^Call: (11) 18000>=15000 ? creep ^Exit: (11) 18000>=15000 ? creep <- preul mainii este mai mic dect suma pe care o dein cei doi Exit: (10) poate(gicu, ferrari) ? creep <- se iese din clauza 2 a predicatului poate , de data aceasta cu succes Exit: (9) cumpara(gicu, ferrari) ? creep <- se iese din cumpara(gicu, ferrari). Yes <- gicu poate cumpra ferrari.

2.3

Unicarea. Operaiile aritmetice

Rezolvarea 2.3.1.

Scriei un predicat care calculeaz media geometric a dou numere introduse de la tastatur. Rezultatul va scris pe ecran. 149

2.3.1

Soluie teoretic

Pentru a calcula media geometric avem nevoie s calculm radical din cele dou numere X i Y. Folosim predicatul predenit sqrt/1 care va evaluat cu valoarea radicalului. Pentru a scrie pe ecran folosim predicatul write/1, iar pentru citirile de la tastatur folosim read/1. Valoarea nal va obinut prin intermediul operatorului is n urma evalurii expresiei sqrt(X*Y). Clauzele vor grupate n acelai predicat n ordinea n care ar i n cadrul unui program structurat.

2.3.2
?- start. X=4. Y=5.

Apel

media geometrica este: 4.47214

2.3.3
start:-

Cod surs

write(X=),read(X), write(Y=),read(Y), M is sqrt(X*Y), write(media geometrica este: ), write(M). 150

2.4

Recursivitate. Predicatele !(cut) i fail

Rezolvarea 2.4.1.

Scriei predicatul prolog puterea(N,K,R) care returneaz n variabila R pe N la puterea K, cu calculul puterii pe retur.

2.4.1

Soluie teoretic

Programul trebuie s deneasc un fapt pentru N la puterea 0 rezultatul este 1, n continuare scdem din K pn cnd K va 0 , facem cut n clauza n care tim ct este N la puterea 0 i pe retur nmulim rezultatul intermediar cu N.

2.4.2

Apel

?- puterea(4,5,R). R = 1024 Yes ?- puterea(3,3,R). R = 27 Yes 151

2.4.3

Cod surs

Codul surs al programului de mai jos se gsete n ierul L4r1.pl puterea(N,0,1):-!. puterea(N,K,R):K1 is K-1, puterea(N,K1,R1), R is R1*N.

2.5

Turnurile din Hanoi. Funciile Fibonacci i Ackermann

2.5.1

Soluie teoretic

N reprezint termenul de rang N din irul lui Fibonacci, vom scdea din N cte o unitate att timp ct N > 0. Pentru a ajunge la termenul de rang n, calculm Xn = Xn1 + Xn2 i reapelm predicatul pentru termenii Xn1 i Xn i N-1. Condiia de oprire este dat de N=0, moment n care se va unica variabila liber F cu valoarea calculat n N1.

2.5.2

Apel

?- bo_tur(4,R). R=2 152

2.5.3

Cod Surs

bo_tur(N, F) :N1 is N - 2, bo_tur(0, 1, N1, F).

bo_tur(_N0, N1, 0, N1). bo_tur(N0, N1, N, F) :N > 0, N2 is N0 + N1, M is N - 1, bo_tur(N1, N2, M, F).

2.6

Liste

Rezolvarea 2.6.1. Scriei un program prolog care simuleaz pe liste reuniunea, intersecia, diferena i diferena simetric pentru mulimi.

2.6.1

Soluie teoretic

Reuniune va un predicat recursiv structurat pe cazuri. Cazul n care un element din prima list este membru n a doua list predicatul va face cut i se va reapela pentru coada primei liste i lista a doua. Dac elementul nu 153

este membru n a doua list atunci el va introdus (la revenirea din apelurile succesive) n lista rezultat. Oprirea apelurilor se va face atunci cnd n prima list nu mai sunt elemente, tot atunci se va unica lista secund cu lista rezultat, pe retur vor adugate la lista rezultat elementele pentru care predicatul member/2 a ntors fail . Intersecia va funciona aproximativ pe acelai principiu cu diferena c elementele care sunt comune vor adugate la lista rezultat, pe retur, n cadrul primei clauze. n cazul diferenei la lista rezultat elementele se adaug pe retur n cadrul primei clauze dac elementele din prima list nu se gsesc i n a doua list. Diferena simetric face uz de predicatele deja denite i se bazeaz pe deniia matematic a acestei relaii.

2.6.2

Apel

?- diferenta([1,5,3,8,6],[4,5,10,7,6],Rezultat). Rezultat = [1, 3, 8] Yes ?- diferenta_simetrica([1,5,3,8,6],[4,5,10,7,6],Rezultat). Rezultat = [1, 3, 8, 4, 10, 7] Yes ?- reuniune([1,5,3,8,6],[4,5,10,7,6],Rezultat). Rezultat = [1, 3, 8, 4, 5, 10, 7, 6] Yes 154

?- intersectie([1,5,3,8,6],[4,5,10,7,6],Rezultat). Rezultat = [5, 6] Yes

2.6.3

Cod surs

Codul surs al programului de mai jos se gsete n ierul L6r1.pl reuniune([],B,B). reuniune([X|A],B,C):member(X,B),!, reuniune(A,B,C). reuniune([X|A],B,[X|C]):- reuniune(A,B,C). intersectie([X|Y],B,Z):member(X,B),!, intersectie(Y,B,Z). intersectie([_|A],B,C):- intersectie(A,B,C). intersectie([],_,[]). diferenta(A,[],A):-!. diferenta([X|A],B,[X|C]):not(member(X,B)),!, dif(A,B,C). diferenta([_|A],B,C):- diferenta(A,B,C). diferenta([],_,[]). diferenta_simetrica(A,B,C):155

diferenta(A,B,X), diferenta(B,A,Y), reuniune(X,Y,C).

2.7

Probleme speciale

Rezolvarea 2.7.1. O rm de cartograe urmrete s coloreze o hart a N tri cu M culori n aa fel nct dou ri vecine s nu e colorate cu aceeai culoare. Scriei un program Prolog care s aeze toate soluiile posibile pentru N i M date.

2.7.1

Soluie teoretic

Predicatul coloreaza(-Lista) returneaz o list de termeni de forma Tara/Culoare unde Tara este numele unei ri i Culoare este culoarea corespunztoare pe hart a acelei ri. El apeleaz setof/3 pentru a construi o list de termeni de forma Tara/Var unde - Tara este numele rii i Var este o variabil, folosete apoi culori/2 pentru a lega ecare variabil Var de o culoare. Predicatul culori ntoarce "Yes" atunci cnd , dndu-i-se o list de elemente de forma Tara/Culoare, se poate gsi o valoare pentru Culoare n aa fel nct Tara careia i este ataat Culoare nu are ri vecine de aceeai culoare. Pentru o list cu Tara/Culoare ind capul listei i coada Rest, coloreaz Rest i apoi selecteaz o valoare pentru Culoare din lista de culori apoi veric daca exist 156

o alt ar n Rest care s e colorat cu aceeai culoare cu cea selectat. Daca nu mai sunt elemente n list atunci ntoarce "Yes". Predicatul tari_vecine(Tara, Tara1) veric dac Tara1 este vecin cu Tara, iar lista_vecini/2 este un predicat folosit pentru a reine n baza de fapte ceva asemntor unei matrici de adiacen.

2.7.2

Apel

?- coloreaza(X). X=[austria/rosu,belgia/verde,danemarca/albastru,franta/rosu, italia/galben,olanda/albastru,portugalia/albastru, spania/galben,elvetia/albastru,germania/galben]

2.7.3

Cod surs

Codul surs prezentat se gsete n ierul L11r1.pl coloreaza(Culoare):setof(Tara_, X ^lista_vecini(Tara,X), Culoare), culori(Culoare). culori([]). culori([Tara/Culoare|Rest]):culori(Rest), member(Culoare, [galben,albastru,rosu,verde]), \+ (member(Tara1/Culoare, Rest), tari_vecine(Tara, Tara1)). tari_vecine(Tara, Tara1):157

lista_vecini(Tara, Vecini), member(Tara1, Vecini). % Reprezentarea vecinilor ecrei ri lista_vecini(portugalia, [spania]). lista_vecini(spania, [portugalia,franta]). lista_vecini(franta, [spania,belgia,elvetia,germania,italia]). lista_vecini(belgia, [franta,germania,olanda]). lista_vecini(olanda, [belgia,germania]). lista_vecini(germania, [olanda,belgia,franta,elvetia,austria,danemarca]). lista_vecini(elvetia, [franta,germania,austria,italia]). lista_vecini(austria, [germania,elvetia,italia]). lista_vecini(italia, [franta,elvetia,austria]). lista_vecini(danemarca, [germania]).

2.8

Fiiere. Baze de date dinamice

Rezolvarea 2.8.1.

Scriei un program Prolog care citete de la tastatur informaii de forma persoana(nume(NumePrenume),telefon(NrTel)). le introduce n baza de date dinamic i le salveaz ntr-un ier specicat de utilizator, care mai apoi poate citit i ncrct n baza de date dinamic. 158

2.8.1
2.8.1.1

Soluia problemei 0.9.1


Soluie teoretic

Citirea de la tastatur se face prin intermediul predicatului sistem read/1. Citim informaiile necesare i folosim predicatul sistem assert/1 pentru a introduce tuplul de forma dorit n baza de date dinamic. Pentru a salva datele trebuie mai nti s le recuperm din baza de date dinamic, apelam predicatul persoana(nume(NumePrenume),telefon(NrTel)). care se va apela pentru toate persoanele introduse n baza de date dinamic, ne asigurm de acest lucru folosind predicatul sistem fail/0 pentru a cauza backtrackingul. ncrcarea ierului presupune citirea de la tastatur a numelui i utilizarea predicatului sistem consult/1 care va ncrca toate clauzele predicatului persoana/2 salvate n ier. Aarea folosete predicatul sistem listing/1 deoarece n urma unui apel de forma listing. vom primi ca rspuns din partea sistemului o list cu toate predicatele compilate de sistem, listing(persoana). va lista numai predicatele persoana. 2.8.1.2 Apel

1 ?- adaug. Nume: ionescu. Telefon:123456. mai adaugati?(y/n)y. Nume: popescu. Telefon:654321. 159

mai adaugati?(y/n)n. Yes

2 ?- asare. :- dynamic persoana/2. persoana(nume(ionescu), telefon(123456)). persoana(nume(popescu), telefon(654321)). Yes

3 ?- salvez_sier. Fisier:agenda. Yes

4 ?- deschid_sier. Fisier:agenda. % agenda.dat compiled 0.00 sec, 676 bytes Yes

5 ?- asare. persoana(nume(ionescu), telefon(123456)). persoana(nume(popescu), telefon(654321)). Yes

160

2.8.1.3

Cod surs

sterg :deschide_sier, prel, st, salvez_in_sier. deschid_sier :write(Fisier:), read(A), concat_atom([A, .dat], B), incarc(B). prel :persoana(nume(A), telefon(B)), fail. prel. incarc(A) :exists_le(B), consult(A). incarc(A). adaug :write(Nume: ), read(A), write(Telefon:), 161

read(B), assert(persoana(nume(A), telefon(B))), write(mai adaugati?(y/n)), read(C), C=y, adaug. adaug. salvez :persoana(nume(A), telefon(B)), write(persoana(nume(A), telefon(B))), write_ln(.), fail. salvez. salvez_sier :write(Fisier:), read(A), concat_atom([A, .dat], B), tell(B), salvez, told. st :write(Nume: ), read(A),

162

retract(persoana(nume(A), telefon(B))). asare :listing(persoana). Rezolvarea 2.8.2. Modicai programul de mai sus referitor la baze de date dinamice astfel nct s nu se adauge de mai multe ori acelai fapt n baza de date.

2.8.2
2.8.2.1

Soluia problemei 0.9.2


Soluie teoretic

Ideea de rezolvare este simpl: nainte de a insera n baza de date vericm dac exist deja faptul respectiv , astfel adugm clauza adauga(X,Y):are(X,Y). care va ntoarce yes dac exist deja un fapt n baza de date i nu se va mai ncerca resatisfacerea celorlalte clauze. Pentru predicatul par/1 adoptm aceeai metod adauga(X,Y):- par(Y),par(X)., dac exist deja clauze n baza de date nu se vor mai introduce altele pentru aceleai valori. 2.8.2.2 ?- apel. Continuati?(da/nu)d. X=6. Y=3. Continuati?(da/nu)d. 163 Apel

X=6. Y=2. Continuati?(da/nu)d. X=6. Y=2. Continuati?(da/nu)n. n urma unei comenzi listing. putem s observm predicatele introduse n baza de date dinamic:

:- dynamic par/1. par(2). par(6).

:- dynamic are/2. are(4, 2). are(6, 3). are(6, 2).

2.8.2.3 start:-

Cod surs

write(X=),read(X),write(Y=),read(Y), M is X mod Y,M=0, adauga(X,Y),go. 164

adauga(X,Y):- are(X,Y). adauga(X,Y):- par(Y),par(X). adauga(X,Y):- assertz(are(X,Y)),fail. adauga(X,Y):- par(Y),assertz(par(X)). adauga(_,_). go:- write(Continuati?(da/nu)),read(R),R=d,start. % go:- retract(are(_,_)),fail. % go:- retract(par(_)),fail. go. apel:- asserta(par(2)),asserta(are(4,2)),go. % introducem faptele par(2) i are(4,2) pentru a avea o deniie pentru aceste predicate n baza de date.

165

166

Capitolul 3 Anexa Predicate

167

3.1
3.1.1

Anexa predicate
Notaiile predicatelor

Numele predicatului este scris cu text ngroat i este urmat de paranteze, iar ntre paranteze lista de argumente. Argumentele al cror nume este precedat de "+" , "-" sau "?" denot faptul c argumentul care ncepe cu "+" este parametru de intrare , cel cu "-" este parametru de ieire, cele cu "?" sunt parametri care pot e de intrare , e de ieire.

3.1.2

ncrcarea ierelor surs

Un ier PROLOG conine clauze i directive, el este ncrcat de obicei folosind predicatele: consult(+Fisier) Citete Fisier ca surs PROLOG. Fisier poate o list de iere caz n care , ecare va consultat pe rnd. ?- consult(sier). % ncarc ier sau sier.pl dac se gsete n directorul curent. ensure_loaded(+Fisier) Dac ierul nu este deja ncrcat, acest predicat este echivalent cu consult/1.

3.1.3

Compararea i unicarea termenilor

Termenii sunt ordonai n ceea ce se cheama ordine standard , aceast ordine este denit dup cum urmeaz: 1. Variabile <Atomi <iruri de caractere <Numere <Termeni 168

2. Variabil veche < Variabil nou 3. Atomii sunt comparai alfabetic. 4. irurile de caractere sunt comparate alfabetic. 5. Numerele sunt comparate dup valoare, numerele ntregi i cele n virgul mobil sunt tratate identic. 6. Termenii compui sunt vericai mai nti dup aritatea lor, apoi dup numele functorului i la nal dup argumente, ncepnd de la cel mai din stnga. +Term1 == +Term2 ntoarce Yes dac Term1 i Term2 sunt echivaleni. +Term1 \ == +Term2 Echivalent cu \ +Term1 == Term2. +Term1 = +Term2 Unic pe Term1 cu Term2 i ntoarce Yes dac unicarea reuete.

3.1.4

Predicate de control

fail ntoarce fail n toate ocaziile. true ntoarce Yes n toate ocaziile. repeat ntoarce Yes pentru a oferi un numr innit de puncte de alegere. ! Cut. Renun la a mai cuta soluii pentru alte valori are unor variabile. +Scop1 , +Scop2 Conjuncie. ntoarce Yes dac Scop1 i Scop2 pot demonstrate. +Scop1 ; +Scop2 Disjuncie. ntoarce Yes dac Scop1 sau Scop2 poate demonstrat. \+ +Scop ntoarce Yes dac Scop nu poate demonstrat. + refer ceva demonstrabil, iar \ este folosit pentru a indica negaia n PROLOG. 169

3.1.5

Baze de date dinamice

assert(+Term) Adaug un fapt la baza de date ca ultim fapt sau clauz a predicatului corespunztor. asserta(+Term) Echivalent cu predicatul de mai sus, dar Term este adugat ca prim clauz sau fapt al unui predicat. assertz(+Clause) Echivalent cu assert/1 . retract(+Term) Atunci cnd Term este atom sau termen el este unicat cu primul fapt sau prima clauz din baza de date , iar faptul sau clauza este ters din baza de date. retractall(+Head) Toate faptele sau clauzele cu care Head se poate unica sunt terse din baza de date. abolish(+PredSpec) terge toate predicatele specicate de PredSpec, unde PredSpec este de forma Predicat/Aritate. Tot ce are legtur cu predicatul specicat este ters din sistem.

3.1.6
3.1.6.1

Intrri i Ieiri
Stilul ISO

open(+SrcDest, +Mode, -Stream, +Optiuni) SrcDest poate un ier, terminalul sau un termen, Mode poate read, write, append sau update, Stream poate , e o variabil care la nal va conine identicatorul de stream, e un atom i n cazul acesta atomul va identicatorul de stream. Optiuni pate : - type(Type) se folosete pentru a putea scrie n mod text, compatibil cu sis170

temul de operare. Dac se folosete tipul binar octeii vor scrii fr a tradui. De menionat c pe sistemele Unix nu se face diferen ntre modul text i binar. - alias(Atom) d unui stream un nume. Atenie la aceast opiune deoarece numele de stream-uri sunt globale. Exemplu: ?- open(data, read, Fd, [alias(input)]). , ...,read(input, Term),... - eof_action(Action) denete ce se ntampl n momentul n care se ajunge la nal de ier - buer(Buering) denete posibilitatea de a avea un buer. - close_on_abort(Bool) nchide stream-ul dac n timpul execuiei programului se apeleaz predicatul abort/0. - lock(LockingMode) ncearc s blocheze ierul pentru ca alte procese s nu l modice n timpul execuiei programului PROLOG. n mod implicit ierul nu va blocat , ns locking mode poate read sau shared, adica alte procese(programe) pot accesa ierul numai pentru citire. open(+SrcDest, +Mode, ?Stream) Este echivalent cu open/4 cu lista de opiuni vid. open_null_stream(?Stream) Deschide un stream vid. Toate funciile sunt active pentru un asemenea stream, dar o ncercare de a citi de pe un astfel de stream returneaz end_of_le. close(+Stream) nchide stream-ul specicat. Dac acest stream este streamul curent pentru intrare/ieire atunci terminalul devine stream curent pentru intrare/ieire.

171

set_stream(+Stream, +Attribute) Seteaz stream-ului atributele prezentate mai sus la predicatul open. Alte predicate utile character_count(+Stream, -Numar) Unic Numr cu indexul curent al caracterului. Pentru stream-urile de intrare acest index este numrul caracterelor citite de cnd a fost deschis stream-ul, iar pentru cele de ieire numrul caracterelor scrise. Primul caracter va avea indexul 0. line_count(+Stream, -Numar) Unic Numar cu numrul liniilor citite sau scrise pe Stream. line_position(+Stream, -Numar) Unic Numar cu poziia de pe linia curent. Se presupune c poziia este 0 dup deschiderea stream-ului , tab-urile se presupun a exista dup ecare al 8-lea caracter, iar backspace reduce din Numar o unitate, Numar ind presupus a pozitiv.

3.1.6.2

Stilul Edinburgh

see(+SrcDest) Deschide SrcDest pentru citire i l face stream-ul curent de intrare. tell(+SrcDest) Deschide SrcDest pentru scriere i l face s e stream-ul curent de ieire. append(+File) Similar cu tell/1, dar poziioneaz pointerul de scriere la nalul ierului. seeing(?SrcDest) i telling(?SrcDest) Nu returneaz numele ierului deschis pentru citire/scriere ci returneaz indenticatorul de stream. 172

seen. nchide stream-ul curent de intrare. told. nchide stream-ul curent de ieire.

3.1.7

Predicate primitive pentru I/O

nl Trece pe linia urmtoare a stream-ului implicit. nl(+Stream) Trece pe linia urmtoare a lui Stream. put(+Char) Scrie un Char pe stream-ul curent. Char este un cod astfel nct 0=<Char=< 255 put(+Stream, +Char) Scrie Char pe Stream. put_byte(+Byte) Echivalent cu put/1. put_byte(+Stream, +Byte) Echivalent cu put/2. put_char(+Char) Echivalent cu put/1. put_char(+Stream, +Char) Echivalent cu put/2. put_code(+Code) Echivalent cu put/1. put_code(+Stream, +Code) Echivalent cu put/2. tab(+Numar) Scrie un Numar de tab-uri pe stream-ul implicit. Numar trebuie s e o expresie care se evalueaz ca un ntreg pozitiv. tab(+Stream, +Numar) Scrie Numar de tab-uri pe Stream ush_output Scrie output-ul pe stream-ul curent. ush_output(+Stream) Scrie output-ul pe Stream. get_byte(-Byte) Citete de pe stream-ul curent de intrare i unic urmtorul octet cu Byte. Byte este un ntreg ntre 1 i 255 i va unicat cu -1 cnd se ajunge la nal de ier. 173

get_byte(+Stream, -Byte) Citete un octet de pe Stream get_code(-Code) Asemntor cu get_byte/1. get_code(+Stream, -Code) Asemntor cu get_byte/2. get_char(-Char) Asemntor cu get_byte/1. get_char(+Stream, -Char) Asemntor cu get_byte/1. get(-Char) Citete un caracter de pe stream-ul curent de intrare. Char va diferit de caracterul vid i va unicat cu -1 dac se ajunge la nal de ier. get(+Stream, -Char) Citete un Char de pe Stream.

3.1.8

Citirea i scrierea termenilor

write(+Term) Scrie Term pe output-ul curent, se pot folosi paranteze i ghilimele. write(+Stream, +Term) Scrie Term pe Stream. writeq(+Term) Scrie Term pe output-ul curent , atomii care au nevoie s e scrii cu ghilimele vor scrii n acest fel. Termenii scrii cu acest predicat pot citii cu read/1. writeq(+Stream, +Term) Scrie Term pe Stream i insereaz ghilimele. print(+Term) Similar cu write/1 , ns acest predicat apeleaz portray/1 pentru ecare sub-termen, iar dac portray/1 ntoarce Yes se presupune c sub-termenul a fost scris. Este folosit pentru a scrie termeni denii de utilizator. print(+Stream, +Term) Scrie Term pe Stream. portray(+Term) Predicat dinamic care poate denit de utilizator pentru a 174

schimba felul n care se comport print/1 . read(-Term) Citete urmtorul termen PROLOG de pe stream-ul curent i l unic cu Term. read(+Stream, -Term) Citete Term de pe Stream.

3.1.9

Predicate pentru operaii cu liste

is_list(+Term) ntoarce Yes dac Term este lista vid sau este legat de o list. memberchk(?Elem, +List) Echivalent cu member/2. length(?Lista, ?Int) ntoarce n Int numrul elementelor din Lista. Poate folosit pentru crearea unei liste ce conine variabile neinstaniate dac variabila Int este legat de o valoare ntreag mai mare sau egal cu 0. Dac este 0 Lista va o list vid. sort(+Lista, -S) ntoarce Yes dac S poate unicat cu o list ce conine elementele din Lista, sortate n mod standard. Dublurile vor eliminate. msort(+List, -Sorted) Echivalent cu sort/2, dar nu elimin dublurile. merge(+Lista1, +Lista2, -Lista3) Lista1 i Lista2 sunt liste sortate n ordine standard a termenilor. Lista3 va unicat cu o list ordonat ce conine elementele din Lista1 i Lista2. merge_set(+Set1, +Set2, -Set3) Set3 va conine elementele din Set1 i Set2 cu dublurile eliminate. 175

3.1.10

Predicate aritmetice

between(+Min, +Max, ?Valoare) Min si Max si Valoare sunt numere ntregi. Dac valoare este instaniat predicatul ntoarce Yes dac

Min=<Valoare=<Max. Dac Valoare este o variabi liber este legat succesiv de toate valorile ntregi dinte Min i Max. succ(?Int1, ?Int2) ntoarce Yes dac Int2 poate legat de o valoare egal cu Int1+1 sau Int2 se evalueaz ca ind echivalent cu Int1+1. plus(?Int1, ?Int2, ?Int3) ntoarce Yes dac Int3= Int1+Int2 , cel puin 2 argumente trebuie intstaniate. +Expr1 > +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr mai mare dect Expr2. +Expr1 < +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr mai mic dect Expr2. +Expr1 =< +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr mai mic sau egal cu Expr2. +Expr1 >= +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr mai mare sau egal cu Expr2. +Expr1 =\= +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr care nu este egal cu Expr2. +Expr1 =:= +Expr2 ntoarce Yes atunci cnd Expr1 se evalueaz cu un numr care este egal cu Expr2. -Numar is +Expr ntoarce Yes cnd Numar a fost unicat cu numrul cu care se evalueaz Expr. 176

?- 1.0 is sin(pi/2). ntoarce No, deoarece sin(pi/2) ntoarce 1.0 dat is va reprezenta ca 1 valoare ntreag, iar dup unicare va ntoarce fail. ?- 1.0 is oat(sin(pi/2)). ntoarce Yes deoarece predicatul oat foreaz rezultatul s e oat. ?- 1.0 =:= sin(pi/2). ntoarce Yes deoarece predicatul =:= consider ambii termeni ca ind expresii.

3.1.11

Funcii aritmetice

+IntExpr1 mod +IntExpr2 mprtire modulo. +IntExpr1 rem +IntExpr2 Restul mpririi ca numr real. abs(+Expr) Modulul expresiei Expr. sign(+Expr) Semnul lui Expr, se evalueaz ca ind -1 dac Expr<0 , 1 dac Expr>0 i 0 daca Expr=0. max(+Expr1, +Expr2) Evalueaz cel mai mare numr din cele dou. min(+Expr1, +Expr2) Evalueaz cel mai mic numr din cele dou. random(+Int) Se evalueaz ca ind un numr ntreg i pentru care 0=<i<Int. round(+Expr) Evalueaz Expr si rotunjete rezultatul. integer(+Expr) Asemntor cu round/1. oat(+Expr) Se evalueaz ca un numr n virgul mobil, n mod normal PROLOG-ul utilizeaz pe ct posibil valori ntregi. Dac este folosit n combinaie cu predicatul is/2 ca al doilea argument returneaz un numr n virgul mobil. n alte contexte operaia nu are efect. oat_fractional_part(+Expr) Se evalueaz ca ind partea fracional 177

a unui numr n virgul mobil. ntoarce 0 dac Expr este numr ntreg, negativ dac Expr este negativ. oat_integer_part(+Expr) Se evalueaz ca ind partea ntreag a unui numr n virgul mobil. ntoarce Expr dac Expr este numr ntreg, negativ dac Expr este negativ. truncate(+Expr) Trunchiaz expresia Expr , asemntor cu

oat_integer_part/1. oor(+Expr) Evalueaz Expr i returneaz cel mai mare ntreg mai mic sau egal cu rezultatul evalurii expresiei Expr. ceiling(+Expr) Evalueaz Expr i returneaz cel mai mic ntreg mai mare sau egal cu rezultatul evalurii expresiei Expr. ceil(+Expr) Asemntor cu ceiling/1. +IntExpr +IntExpr Deplasare la dreapta pe bii. +IntExpr +IntExpr Deplasare la stnga pe bii. +IntExpr \/ +IntExpr Operaia "sau" pe biti. +IntExpr /\ +IntExpr Operaia "i" pe biti. +IntExpr xor +IntExpr Operaia "sau exclusiv" pe biti. \ +IntExpr Negaie pe bii. sqrt(+Expr) Radicalul expresiei Expr. sin(+Expr) Sinusul expresiei Expr. cos(+Expr) Cosinusul expresiei Expr. tan(+Expr) Tangenta expresiei Expr. asin(+Expr) Arcsinusul expresiei Expr.

178

acos(+Expr) Arccosinusul expresiei Expr. atan(+Expr) Arctangenta expresiei Expr. log(+Expr) ntoarce logaritmul natural al expresiei Expr. log10(+Expr) ntoarce logaritmul n baza 10 al expresiei Expr. exp(+Expr) ntoarce e la puterea Expr. +Expr1 ** +Expr2 ntoarce Expr1 la puterea Expr2. +Expr1 ^+Expr2 Identic cu **/2. pi Constanta matematic pi (3.141593). e Constanta matematic e (2.718282).

3.1.12

Urmrirea execuiei programului

trace Pornete urmrirea programului. tracing ntoarce Yes atunci cnd trace este activ. notrace Oprete trace-ul. guitracer Instaleaz puncte cheie n program pentru a putea urmrit trace-ul pe o interfa grac. noguitracer Contrarul lui guitracer. trace(+Pred) Echivalent cu trace(Pred, +all). trace(+Pred, +Ports) Urmrete predicatul Pred pentru porturile specicate, porturile valide sunt: call, redo, exit, fail. notrace(+Scop) Apeleaz Scop dar suspend debugger-ul ct timp se execut Scop. debug Pornete debugger-ul. 179

nodebug Oprete debugger-ul. debugging Aeaz informaii despre starea debugger-ului.

180

Glosar
int, 36 int vid, 36 abordare descriptiv, 93 imperativ, 93 Ackermann, 147 algoritmi de unicare, 58 aritate, 24 backtracking, 115 baza Herbrand, 48 recticat, 69 capul clauzei, 35 cel mai general unicator, 59 clauz, 34 clauz denit, 36 clauz Horn, 36 clauz unitar, 36 clauz vid, 34 clauza de baz, 127 echivalen logic, 40 fail, 128 familia formulelor, 26 fapt, 36 fapte PROLOG, 96 Fibonacci, 146 181 domeniu nevid, 31 clauza recursiv, 127 comentariu PROLOG, 114 comenzi SWI-Prolog, 98 conectori logici, 22 consecin logic, 39 control, 92 corpul clauzei, 35 cuanticator existenial, 23 cuanticator universal, 23 cut, 128

Forma Normal Prenex, 42 Forma Normal Skolem, 45 format relaional, 71 formul, 25 formul nchis, 26 formul atomic, 25 formul derivabil, 41 formul prenex, 42 graf de dependen, 71

predicat extensional, 72 predicat intensional, 72 predicatul cut, 128 predicatul fail, 128 predicatul read, 113 predicatul write, 113 program DATALOG, 66 program denit, 37 program logic, 37 program recticat, 69

guitracer, 112 program recursiv, 72 inferen, 41 rangul unei formule, 27 interogri PROLOG, 95 recursivitate, 127 interpretare, 31 regul consistent, 41 interpretare Herbrand, 48 regul PROLOG, 97 Legea lui DeMorgan, 40 liste PROLOG, 151 literal, 34 scop, 36 Loewenheim-Skolem, 45 scopuri PROLOG, 95 logic, 92 simboluri, 22 model, 76 model Herbrand, 49 model minimal, 76 simboluri funcionale, 24 simboluri predicative, 22 SLD-arbore, 54 182 regulile de inferen, 41 rezolvent, 54

subformul, 25 substituie, 27 subtermen, 25 termen, 24 termen de baz, 26 termen ground, 26 termeni PROLOG, 106 trace, 111 transformare n forma prenex, 43 turnurile din Hanoi, 143 unicarea variabilelor, 119 unicatori, 58 univers Herbrand, 47 variabil, 21 variabil legat, 26 variabile anonime, 108 variabile limitate, 65

183

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