Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ===== TODO ===== Scopul laboratorului: - TODO - TODO ==== Cut ==== === Green cut === === Red cut === ==== Negation as failure ==== ==== Colectare rezultate ==== Fie următoarea bază de cunoștiințe genealogice: <code prolog> % File: norse.pl father(buri, borr). father(borr, odin). father(borr, vili). father(borr, ve). father(odin, thor). father(odin, baldr). mother(bestla, odin). mother(bestla, vili). mother(bestla, ve). mother(jorth, thor). mother(frigg, baldr). </code> Putem defini ușor un predicat pentru a determina relația părinte-copil: <code prolog> parent(P, C) :- mother(P, C). parent(P, C) :- father(P, C). </code> După cum ați observat până acum, predicatul definit e versatil; poate fi folosit pentru a verifica o relație, pentru a determina părinții unei persoane, pentru a determina copiii unei persoane, sau pentru a genera toate perechile părinte-copil din baza de cunoștiințe: <code> ?- parent(odin, thor). true. ?- parent(buri, odin). false. ?- parent(borr, C). C = odin ; C = vili ; C = ve. ?- </code> Pentru ultima interogare, există mai multe posibilități de unificare a variabilei ''C'', iar prolog ni le oferă pe rând (introducând '';'' interactiv, primim următoarea soluție). Uneori, este util să putem colecta toate aceste soluții într-o listă pe care putem, ulterior, face alte procesări. În continuare, vom studia trei predicate pentru a realiza acest lucru. === findall === [[http://www.swi-prolog.org/pldoc/man?predicate=findall/3|findall/3]] este un predicat care primește un tipar de rezultate, un goal de demonstrat și o listă de ieșire care va conține toate rezultatele construite pe baza tiparului, pentru care goal-ul primit este adevărat. Cel mai simplu tipar util este o singură variabilă, care se regăsește în scopul primit. <code> ?- findall(C, parent(borr, C), L). L = [odin, vili, ve]. ?- </code> Dacă nu există niciun rezultat, ''findall/3'' generează o listă vidă: <code> ?- findall(C, parent(baldr, C), L). L = []. ?- </code> Deasemenea primul argument poate fi un termen compus: <code> ?- findall(child(C, borr), parent(borr, C), L). L = [child(odin, borr), child(vili, borr), child(ve, borr)]. ?- </code> === bagof === [[http://www.swi-prolog.org/pldoc/man?predicate=bagof/3|bagof/3]] este un predicat asemănător cu ''findall/3'', având aceeași semnificație a parametrilor. Diferența dintre cele două este vizibilă atunci când introducem în goal o variabilă care nu apare în template. <code> ?- findall(C, parent(P, C), L). L = [odin, vili, ve, thor, baldr, borr, odin, vili, ve|...]. ?- </code> Observăm că ''findall/3'' ne întoarce o singură listă cu toate rezultatele posibile. În unele cazuri, ar fi util ca, pentru fiecare părinte ''P'', să primim o altă listă. Pentru asta folosim ''bagof'': <code> ?- bagof(C, parent(P, C), L). P = bestla, L = [odin, vili, ve] ; P = borr, L = [odin, vili, ve] ; P = buri, L = [borr] ; P = frigg, L = [baldr] ; P = jorth, L = [thor] ; P = odin, L = [thor, baldr]. ?- </code> Rezultatele sunt generate în stilul clasic, necesitând '';'' interactiv. Putem apoi să le colectăm folosind din nou ''bagof/3'': <code> ?- bagof(children(P, L), bagof(C, parent(P, C), L), R). R = [children(bestla, [odin, vili, ve]), children(borr, [odin, vili, ve]), children(buri, [borr]), children(frigg, [baldr]), children(jorth, [thor]), children(odin, [thor, baldr])]. ?- </code> <note> În ultima interogare, nu contează dacă predicatul folosit în exterior este ''bagof/3'' sau ''findall/3''. Goal-ul de demonstrat (''bagof(C, parent(P, C), L)'') nu conține variabile "din afară". </note> Ca urmare a felului de funcționare, o diferență notabilă între ''findall/3'' și ''bagof/3'' este că, atunci când goal-ul nu poate fi satisfăcut, ''findall/3'' reușește, generând o listă vidă, iar ''bagof/3'' eșuează. <code> ?- findall(C, parent(thor, C), L). L = []. ?- bagof(C, parent(thor, C), L). false. ?- </code> === setof === Fie următorul predicat, pentru a stabili care două persoane au un copil în comun: <code prolog> common_child(F, M) :- father(F, C), mother(M, C). </code> Am vrea să generăm o listă cu toate persoanele care au un copil cu Odin. Ne folosim de predicatele ''bagof/3'' și ''common_child/2'': <code> ?- bagof(M, common_child(odin, M), L). L = [jorth, frigg]. ?- </code> Obținem rezultatul dorit. Ce se întâmplă însă dacă două persoane au în comun mai mulți copii? <code> ?- bagof(M, common_child(borr, M), L). L = [bestla, bestla, bestla]. ?- </code> Rezultatul nu este ideal, deoarece //conține duplicate//. [[http://www.swi-prolog.org/pldoc/doc_for?object=setof/3|setof/3]] este un predicat asemănător cu ''bagof'', având aceeași semnificație a parametrilor, dar care generează o listă //sortată, fără duplicate// (mai multe informații despre ce implică sortarea, puteți găsi [[http://www.swi-prolog.org/pldoc/man?section=standardorder|aici]]). <code> ?- setof(M, common_child(odin, M), L). L = [frigg, jorth]. ?- setof(M, common_child(borr, M), L). L = [bestla]. ?- </code> În rest, ''setof/3'' se comportă ca ''bagof/3''; pentru variabilele din goal care nu apar în template generează soluții separate și eșuează dacă nu există niciuna: <code> ?- setof(M, common_child(F, M), L). F = borr, L = [bestla] ; F = odin, L = [frigg, jorth]. ?- setof(M, common_child(thor, M), L). false. ?- </code> ==== Exerciții ==== ==== Recommended Reading ==== * [[https://mitpress.mit.edu/books/art-prolog-second-edition|The Art of Prolog - II. The Prolog Language - 11. Cuts and Negation]] * [[http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlch5|Learn Prolog Now! - Chapter 5 Arithmetic]] * [[http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlch6|Learn Prolog Now! - Chapter 6 More Lists]] * [[http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlch10|Learn Prolog Now! - Chapter 10 Cuts and Negation]] * [[http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlch11|Learn Prolog Now! - Chapter 11 Database Manipulation and Collecting Solutions]]