This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
laboratoare:10-prolog-introducere [2016/05/09 21:59] mihai_dan.masala |
laboratoare:10-prolog-introducere [2016/05/24 15:46] (current) mihai_dan.masala |
||
---|---|---|---|
Line 15: | Line 15: | ||
Folosim faptele pentru a exprima un adevar. De exemplu vrem sa "definim" ca Gigel este barbat. Pentru a defini o regula este suficient sa ii definim numele(de preferat sugestiv) si sa ne hotaram care este "actorul". | Folosim faptele pentru a exprima un adevar. De exemplu vrem sa "definim" ca Gigel este barbat. Pentru a defini o regula este suficient sa ii definim numele(de preferat sugestiv) si sa ne hotaram care este "actorul". | ||
In cazul de fata Gigel este actorul iar numele regulii este barbat => **barbat(gigel).** \\ | In cazul de fata Gigel este actorul iar numele regulii este barbat => **barbat(gigel).** \\ | ||
- | Observati **numele regulii** - barbat - **numele actorului** - gigel(cu litera mica!) - si **punctul** de la sfarsit regulii(echivalent ";") | + | Observati **numele regulii** - barbat - **numele actorului** - gigel(cu litera mica!) - si **punctul** de la sfarsitul regulii(echivalent ";") |
==== Interogari ==== | ==== Interogari ==== | ||
Line 21: | Line 21: | ||
Interogarile sunt metodele prin care noi putem sa ii cerem ceva programului. Pentru a "intreba" ceva este suficient sa scriem in interpretor ce vrem sa aflam. \\ | Interogarile sunt metodele prin care noi putem sa ii cerem ceva programului. Pentru a "intreba" ceva este suficient sa scriem in interpretor ce vrem sa aflam. \\ | ||
De exemplu vrem sa aflam daca Gigel este barbat, pur si simplu "intrebam" in interpretor **barbat(gigel).** (observati numele regulii, actorul si punctul de la final!).\\ | De exemplu vrem sa aflam daca Gigel este barbat, pur si simplu "intrebam" in interpretor **barbat(gigel).** (observati numele regulii, actorul si punctul de la final!).\\ | ||
- | Raspunsul dat de programul nostru este **yes**. Raspunsul este afirmativ deoarece acest fapt exista in cadrul programului nostru in setul de fapte si reguli (denumit in continuare baza de cunostinte). \\ \\ | + | Raspunsul dat de programul nostru este **true**. Raspunsul este afirmativ deoarece acest fapt exista in cadrul programului nostru in setul de fapte si reguli (denumit in continuare baza de cunostinte). \\ \\ |
Ce va raspunde programul la urmatoarea interogare: **copil(gigel).***? \\ | Ce va raspunde programul la urmatoarea interogare: **copil(gigel).***? \\ | ||
- | Raspunsul este **no** (nu avem nicio informatie in baza de cunostinte legata de varsta lui Gigel). \\ \\ | + | Raspunsul este **false** (nu avem nicio informatie in baza de cunostinte legata de varsta lui Gigel). \\ \\ |
Dar la intrebarea **femeie(andreea)**? De ce?\\ | Dar la intrebarea **femeie(andreea)**? De ce?\\ | ||
Line 31: | Line 31: | ||
barbat(gigel).\\ | barbat(gigel).\\ | ||
insurat(gigel).\\ | insurat(gigel).\\ | ||
- | **sot(gigel):- barbat(gigel),insurat(gigel)**. Ce spune aceasta regula? Ce inseamna **,**? \\ | + | **sot(gigel):- barbat(gigel),insurat(gigel)**. Ce spune aceasta regula? Ce inseamna **","**? \\ |
- | Tocmai am definit o regula care spuna ca Gigel este sot daca Gigel este barbat **si** daca Gigel este insurat. Virgula este modul in care se exprima conjunctia logica in Prolog \\ | + | Tocmai am definit o regula care spune ca Gigel este sot daca Gigel este barbat **si** daca Gigel este insurat. Virgula este modul in care se exprima conjunctia logica in Prolog \\ |
- | Care va fi raspunsul la urmatoarea interogare: **sot(gigel).** ? | + | Care este raspunsul la urmatoarea interogare: **sot(gigel).** ? |
+ | ==== Exemplu ==== | ||
+ | Fie urmatoarea baza de cunostinte: | ||
+ | femeie(ioana). | ||
+ | barbat(mihai). | ||
+ | barbat(andrei). | ||
+ | casatorit(mihai,ioana). | ||
+ | parinte(ioana,andrei). | ||
+ | parinte(mihai,andrei). | ||
+ | Observam ca am definit fapte cu aritate doi(nu suntem limitati la fapte/reguli cu aritate 1!). | ||
+ | Care este raspunsul la urmatoarea interogare: **casatorit(ioana,mihai).**? \\ | ||
- | ==== Liste & diverse ==== | + | Vrem sa definim o regula care sa ne spuna daca Mihai este tata: **tata(mihai):- barbat(mihai), parinte(mihai,andrei).**(Mihai este barbat si este tatal lui Andrei).\\ |
+ | Problema cu aceasta abordare este ca Mihai poate sa fie parintele mai multor copii, nu doar al lui Andrei, ceea ce nu il invalideaza ca si tata. Cum rezolvam aceasta problema? Ne trebuie o "generalizare" a lui Andrei. | ||
+ | Aceasta generalizare o vom "implementa" folosind **variabile**. | ||
+ | ==== Variabile ==== | ||
+ | Variabilele in Prolog sunt stringuri care incep cu litera mare.\\ | ||
+ | Noua regula devine: **tata(mihai):- barbat(mihai), parinte(mihai,Copil).**\\ | ||
+ | Prolog va incerca(prin backtracking) sa lege variabile Copil la orice actor care respecta faptul parinte(mihai,Copil) (in cazul nostru doar andrei). \\ | ||
+ | Ce se intampla daca baza noastra de cunostinte contine (mult) mai multe fapte si reguli si vrem sa aflam care sunt toate mamele.?\\ | ||
+ | **mama(Mama):- femeie(Mama), parinte(Mama,Copil).** Interogand **mama(Mama).** variabila Mama va lua, pe rand, totii actorii care satisfac cele doua reguli.(Interogarea intoarce cate o valoare pe rand. Pentru e trece la urmatoarea valoare folositi **;**) \\ | ||
+ | |||
+ | Cum procedam daca vrem sa aflam un rezultat in urma unei interogari? Vom folosi variabile. Pentru a exemplifica acest lucru vom recurge la aritmetica.\\ | ||
+ | |||
+ | Aritmetica in Prolog are o particularitate legate de sintaxa: 7 + 2 = 9 (in limbaj natural) se traduce in 9 is 7 + 2 (in Prolog). \\ | ||
+ | Pentru a obtine un rezultat putem forma urmatoarea interogare: ** R is 2+3.** (R va unifica cu 5). \\ | ||
+ | |||
+ | Sa observam urmatoarea regula: **compute_sum(A,B,Sum):- Sum is A+B.**. Avem o regula care calculeaza suma primelor doua variabile si "salveaza" rezultatul in ultima variabila. Cand avem de scris reguli cu input si output este important sa fiti consecventi in alegerea unei conventii(in exemplul oferit variabilele de intrare sunt pozitionate la inceputul regulii pe cand cele de iesire sunt la sfarsitul cererii). | ||
+ | |||
+ | ==== Liste ==== | ||
+ | Un concept extrem de util in Prolog este cel de lista. In Prolog, o lista se declara in felul urmator: | ||
+ | <code> | ||
+ | [1, 2, 3]. | ||
+ | [1 | [2 | [3 | []]]]. ([1,2,3]) | ||
+ | [mihai, ioana, andrei]. | ||
+ | [mihai, parinte(ioana), X]. | ||
+ | [1, [2, copil(andrei)], [], [X, Y, Z]]. | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Din penultimul exemplu se poate vedea ca o lista poate contine atat variabile, cat si constante sau itemi complecsi. Din ultimul exemplu se poate vedea ca o lista poate contine ca element o alta lista. \\ | ||
+ | Ne propunem in continuare sa obtinem primul element dintr-o lista, precum si restul listei(**head** si **tail** din Haskell). Pentru aceasta, se va folosi unificarea din Prolog. | ||
+ | |||
+ | <code> | ||
+ | ?- [H|L] = [1, 2, 3]. | ||
+ | H = 1, | ||
+ | L = [2,3]. | ||
+ | </code> | ||
+ | In urma comenzii, capul listei va fi legat la variabila **X**, iar restul listei va fi legata la variabila **Y**. | ||
+ | |||
+ | <code> | ||
+ | ?- [H1,H2|_] = [1, 2, 3]. | ||
+ | H1 = 1, | ||
+ | H2 = 2. | ||
+ | </code> | ||
+ | In urma comenzii, primele doua elemente ale liste vor fi legate la variabilele **H1** si **H2**. Simbolul **'_'** (underscore) are un comportament similar cu cel din Haskell si anume cel de variabila anonima. Folosim acest simbol cand nu dorim sa legam ceva la o variabila. | ||
+ | |||
+ | Incercam in continuare sa calculam lungimea unei liste. \\ | ||
+ | Incepem prin a defini o regula prin care determinam daca ceva reprezinta o lista. | ||
+ | <code> | ||
+ | empty(L) :- L = []. | ||
+ | isList(L) :- empty(L). | ||
+ | isList([H|T]) :- isList(T). | ||
+ | </code> | ||
+ | |||
+ | Ne dam seama ca putem simplifica codul. | ||
+ | <code> | ||
+ | isList([]). | ||
+ | isList([_|T]) :- isList(T). | ||
+ | </code> | ||
+ | |||
+ | Calculam acum lungimea unei liste. | ||
+ | <code> | ||
+ | len(L, R) :- empty(L), R = 0. | ||
+ | len([H|T], R) :- isList(L), len(T, R1), R = R1 + 1. | ||
+ | </code> | ||
+ | Observati ca secventa nu functioneaza cum ar trebui pentru ca unificarea previne evaluarea lui R. Varianta finala a codului este: | ||
+ | |||
+ | <code> | ||
+ | len([], 0). (unificare implicita) | ||
+ | len([_|T], R) :- len(T, R1), R is R1+1. | ||
+ | </code> | ||
+ | |||
+ | Cum determinam daca un element apartine unei liste? | ||
+ | <code> | ||
+ | contains(E, [E|_]). | ||
+ | contains(E, [X |T]) :- E \= X, contains(E, T). | ||
+ | |||
+ | ?- contains(1, [1,2,3]). | ||
+ | true; | ||
+ | false. | ||
+ | </code> | ||
+ | De ce prima data obtinem **true**, iar dupa aceea **false**? | ||
+ | ==== Exercitii liste & diverse ==== | ||
- Definiti predicatul ''firstTwo(X,Y,L)'' care leaga variabilele ''X'', ''Y'' la primele doua elemente din lista ''L'', daca acestea exista. | - Definiti predicatul ''firstTwo(X,Y,L)'' care leaga variabilele ''X'', ''Y'' la primele doua elemente din lista ''L'', daca acestea exista. | ||
- | - Definiti predicatul ''contains(E,L)'' care verifica daca elementul la care este legat ''E'' exista in lista ''L''. | + | - Definiti predicatul ''notContains(E,L)'' care verifica daca elementul la care este legat ''E'' nu exista in lista ''L''. |
- | - Definiti predicatul ''notcontains(E,L)''. | + | |
* Poate acest predicat sa fie folosit pentru a genera toate elementele care nu sunt in ''L''? Justificati raspunsul. | * Poate acest predicat sa fie folosit pentru a genera toate elementele care nu sunt in ''L''? Justificati raspunsul. | ||
- Definiti predicatul ''unique(L1,L2)''. ''L2'' este lista ''L1'' fara elemente duplicate. | - Definiti predicatul ''unique(L1,L2)''. ''L2'' este lista ''L1'' fara elemente duplicate. | ||
Line 65: | Line 155: | ||
==== Resurse (functii matematice) ==== | ==== Resurse (functii matematice) ==== | ||
* [[http://www.swi-prolog.org/man/arith.html|Functii utile in Prolog]] | * [[http://www.swi-prolog.org/man/arith.html|Functii utile in Prolog]] | ||
+ | * [[http://www.learnprolognow.org/lpnpage.php?pageid=online| Tutorial Prolog]] | ||
=== Solutii === | === Solutii === | ||
[[https://github.com/Programming-Paradigms/Labs/archive/master.zip|Solutii]] | [[https://github.com/Programming-Paradigms/Labs/archive/master.zip|Solutii]] |