This shows you the differences between two versions of the page.
|
pp:23:laboratoare:prolog:intro [2023/05/01 17:47] bot.pp |
pp:23:laboratoare:prolog:intro [2023/05/10 07:30] (current) alexandru.bala [Tipuri de date] |
||
|---|---|---|---|
| Line 19: | Line 19: | ||
| ==== Prolog ==== | ==== Prolog ==== | ||
| - | Prolog a fost unul dintre [[https://en.wikipedia.org/wiki/Logic_programming#History|primele]] limbaje de programare **logice** și rămâne în continuare cel mai popular astfel de limbaj, folosit în demonstratoarele de teoreme și utilizat inclusiv pentru o parte din implementarea sistemului IBM Watson. Permite separarea datelor de procesul de inferență, programele fiind scrise într-un stil **declarativ** și uniform. Impactul principal l-a avut în cercetare, în domeniul inteligenței artificiale, dar a rămas un punct de inspirație pentru limbajele de după. | + | [[https://en.wikipedia.org/wiki/Prolog|Prolog]] a fost unul dintre [[https://en.wikipedia.org/wiki/Logic_programming#History|primele]] limbaje de programare **logice** și rămâne în continuare cel mai popular astfel de limbaj, folosit în demonstratoarele de teoreme și utilizat inclusiv pentru o parte din implementarea sistemului IBM Watson. Permite separarea datelor de procesul de inferență, programele fiind scrise într-un stil **declarativ** și uniform. Impactul principal l-a avut în cercetare, în domeniul inteligenței artificiale, dar a rămas un punct de inspirație pentru limbajele de după. |
| Numele limbajului este o abreviere pentru //programmation en logique//, și este bazat pe calcul cu predicate. | Numele limbajului este o abreviere pentru //programmation en logique//, și este bazat pe calcul cu predicate. | ||
| Line 29: | Line 29: | ||
| > Toții peștii respiră. (prin branhii) | > Toții peștii respiră. (prin branhii) | ||
| - | $$\forall X . (peste(X) \Rightarrow respira(X))$$ | + | //∀ X . (peste(X) → respira(X))// |
| > Unii pești au o respirație aeriană. (prin plămâni) | > Unii pești au o respirație aeriană. (prin plămâni) | ||
| - | $$\exists X. (peste(X) \land respiraAer(X))$$ | + | //∃ X . (peste(X) ∧ respira(X))// |
| Limbajul restricționează această logică doar la folosirea de clauze Horn. O clauză este o disjuncție (o operație //sau//) peste predicate sau și negații de predicate. O **clauză Horn** conține un singur literal pozitiv, ceea ce înseamnă că este o implicație care nu poate avea drept concluzie o disjuncție între mai multe predicate. (Vezi cursul pentru o înțelegere mai bună.) | Limbajul restricționează această logică doar la folosirea de clauze Horn. O clauză este o disjuncție (o operație //sau//) peste predicate sau și negații de predicate. O **clauză Horn** conține un singur literal pozitiv, ceea ce înseamnă că este o implicație care nu poate avea drept concluzie o disjuncție între mai multe predicate. (Vezi cursul pentru o înțelegere mai bună.) | ||
| - | $$\begin{align} A_1 \land A_2 \land \dots \land A_n &\Rightarrow A \ true &\Rightarrow B \end{align}$$ | + | A_1 ∧ A_2 ∧ ... ∧ A_n → A |
| + | |||
| + | true → B | ||
| Deci următoarea implicație **nu** poate fi transcrisă direct într-o regulă în Prolog, pentru că are ca implicație o disjuncție dintre două predicate. | Deci următoarea implicație **nu** poate fi transcrisă direct într-o regulă în Prolog, pentru că are ca implicație o disjuncție dintre două predicate. | ||
| - | $$\begin{rcases} int(a) \ int(b) \ a \neq 0 \ sum(a, b) = 0 \end{rcases} \Rightarrow negative(a) \lor negative(b) $$ | + | int(a) ∧ int(b) ∧ a ≠ 0 ∧ sum(a, b) = 0 → negative(a) ∨ negative(b) |
| ==== SWI-Prolog ==== | ==== SWI-Prolog ==== | ||
| Line 51: | Line 53: | ||
| ===== Sintaxă și semantică ===== | ===== Sintaxă și semantică ===== | ||
| - | Programele scrise în Prolog descriu relații exprimitate prin clauze. Există două tipuri de clauze: | + | Programele scrise în Prolog descriu relații exprimate prin clauze. Există două tipuri de clauze: |
| * axiome sau fapte (en. //facts//) | * axiome sau fapte (en. //facts//) | ||
| Line 91: | Line 93: | ||
| ==== Termeni ==== | ==== Termeni ==== | ||
| - | În Prolog orice valoare se numește [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:term|termen]]. Tipuri simpli de termeni: constante, sau mai bine zis //atomi// simbolici, întregi, numere în virgulă mobilă sau termeni compuși. | + | În Prolog orice valoare se numește [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:term|termen]]. Tipuri simpli de termeni: |
| - | Cuvântul [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:structure|structură]] este un sinonim pentru termenul [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:compound|compus]]. | + | * Constante textuale, sau mai bine zis //atomi//<code> |
| + | nume, ion, popescu | ||
| - | <code> | + | </code> |
| + | * Numere întregi/numere în virgulă mobilă | ||
| + | * Variabile (vom detalia mai departe)<code> | ||
| + | ?- om(X). | ||
| + | X = socrate. | ||
| + | |||
| + | </code> | ||
| + | * Termeni [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:compound|compuși]].<code> | ||
| % exemplu structură | % exemplu structură | ||
| client(nume(ion, popescu), carte(aventuri, 2002)). | client(nume(ion, popescu), carte(aventuri, 2002)). | ||
| </code> | </code> | ||
| - | Puteți considera momentan că sintactic singura diferență este că predicatele nu sunt transmise ca argumente, aceasta fiind o [[https://stackoverflow.com/questions/28972038/prolog-structurecomplex-term-vs-predicate-i-dont-really-get-the-difference|discuție]] mai subtilă ce ține de reprezentarea internă a implementării. | ||
| - | Consultați [[https://www.swi-prolog.org/pldoc/man?section=glossary|**glosarul**]] în caz de orice neînțelegere!!! | + | Cuvântul [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:structure|structură]] este un sinonim pentru termenul compus. |
| + | |||
| + | Puteți considera momentan că singura diferență, sintactică, este că predicatele nu sunt transmise ca argumente, aceasta fiind o [[https://stackoverflow.com/questions/28972038/prolog-structurecomplex-term-vs-predicate-i-dont-really-get-the-difference|discuție]] mai subtilă ce ține de reprezentarea internă a implementării. | ||
| + | |||
| + | Consultați [[https://www.swi-prolog.org/pldoc/man?section=glossary|**glosarul**]] pentru orice detalii suplimentare. | ||
| ==== Scopuri și variabile ==== | ==== Scopuri și variabile ==== | ||
| Line 108: | Line 121: | ||
| Când rulăm interogări despre termeni și relațiile dintre ei spunem informal că demonstrăm sau obținem informații pornind de la "baza noastră de date" (de la axiome, de la fapte). | Când rulăm interogări despre termeni și relațiile dintre ei spunem informal că demonstrăm sau obținem informații pornind de la "baza noastră de date" (de la axiome, de la fapte). | ||
| - | Calcul se face prin încercarea de a satisface[^1] //scopuri// (en. //goals//). | + | Calcul se face prin încercarea de a satisface [^1] //scopuri// (en. //goals//). |
| **OBSERVAȚIE**: Când am interogat dacă Socrate este muritor, procesul de execuție a returnat ''%%false%%'' deoarece **nu** se putea satisface acest scop. Nu înseamnă că el este nemuritor. Aceasta este //ipoteza lumii închise// -- orice nu poate fi demonstrat ca adevărat va fi considerat fals. | **OBSERVAȚIE**: Când am interogat dacă Socrate este muritor, procesul de execuție a returnat ''%%false%%'' deoarece **nu** se putea satisface acest scop. Nu înseamnă că el este nemuritor. Aceasta este //ipoteza lumii închise// -- orice nu poate fi demonstrat ca adevărat va fi considerat fals. | ||
| Line 126: | Line 139: | ||
| Observați că în a doua interogare am făcut primul nostru calcul util, folosind o variabilă, ''%%X%%''. Argumentul nu mai este o valoare particulară, ci sistemul de execuție încearcă **legarea** ei la diferite constante sau atomi. Prin convenție numele variabilelor (''%%X%%'') începe cu literă mare iar numele atomilor (''%%leulDinNemeea%%'', ''%%rhesus%%'') începe cu literă mică. | Observați că în a doua interogare am făcut primul nostru calcul util, folosind o variabilă, ''%%X%%''. Argumentul nu mai este o valoare particulară, ci sistemul de execuție încearcă **legarea** ei la diferite constante sau atomi. Prin convenție numele variabilelor (''%%X%%'') începe cu literă mare iar numele atomilor (''%%leulDinNemeea%%'', ''%%rhesus%%'') începe cu literă mică. | ||
| - | Așa cum v-ați obișnuit de la Haskell, și Prolog permite folosirea de variablie [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:anonymous|anonime]], ''%%_%%''. Multiple folosiri ale lui ''%%_%%'' nu se leagă la același termen. | + | Așa cum v-ați obișnuit de la Haskell, și Prolog permite folosirea de variabile [[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:anonymous|anonime]], ''%%_%%''. Multiple folosiri ale lui ''%%_%%'' nu se leagă la același termen. |
| <code> | <code> | ||
| Line 132: | Line 145: | ||
| X = rhesus, | X = rhesus, | ||
| Y = tracia. | Y = tracia. | ||
| + | |||
| + | ?- muritor(X), rege(X, _, _). | ||
| + | X = rhesus. | ||
| </code> | </code> | ||
| Line 166: | Line 182: | ||
| * Axiomele sunt reguli fără corp. | * Axiomele sunt reguli fără corp. | ||
| * Am folosit operatorul ''%%,%%'', "și" logic ($\land$), deci a doua regulă a predicatului ''%%muritor(?Cine)%%'' are două premise. | * Am folosit operatorul ''%%,%%'', "și" logic ($\land$), deci a doua regulă a predicatului ''%%muritor(?Cine)%%'' are două premise. | ||
| - | * Am folosit [[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%2B)/1|operatorul ''%%\+%%'']] pe care îl puteți trata ca pe o negație pentru moment. | + | * Am folosit operatorul ''%%\+%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%2B)/1|doc]]) pe care îl puteți trata ca pe o negație pentru moment. |
| Rulăm următoarele interogări: | Rulăm următoarele interogări: | ||
| Line 200: | Line 216: | ||
| </code> | </code> | ||
| - | Deci mai întâi încearcă demonstrarea primei reguli pentru predicatul ''%%muritor%%'' și eșuează. Prima premisă din a doua regulă este adevărată (''%%viu(X)%%''). Observăm că **eșecul demonstrației** scopului ''%%zeu(hercule)%%'' determină adevărată a doua premisă (''%%\+ zeu(X)%%''). Cele două premise fiind puse în conjuncție, considerăm că Hercule este muritor. | + | Observăm că mai întâi încearcă demonstrarea primei reguli pentru predicatul ''%%muritor%%'' și eșuează. Prima premisă din a doua regulă este adevărată (''%%viu(X)%%''). Observăm că **eșecul demonstrației** scopului ''%%zeu(hercule)%%'' determină adevărată a doua premisă (''%%\+ zeu(X)%%''). Cele două premise fiind puse în conjuncție, considerăm că Hercule este muritor. |
| === Negația ca eșec în demonstrație === | === Negația ca eșec în demonstrație === | ||
| Line 246: | Line 262: | ||
| // verificarea celei de-a doua condiții se efectuază doar dacă se trece de prima | // verificarea celei de-a doua condiții se efectuază doar dacă se trece de prima | ||
| if (ptr != NULL && ptr->field != ILLEGAL_VALUE) { | if (ptr != NULL && ptr->field != ILLEGAL_VALUE) { | ||
| - | // do something usefull | + | // do something useful |
| } | } | ||
| Line 271: | Line 287: | ||
| === Diferitele tipuri de "egalitate" === | === Diferitele tipuri de "egalitate" === | ||
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D)/2|''%%=%%'']]: operatorul de unificare. Dacă operanzii nu conțin variabile, atunci verifică identitatea operanzilor; altfel, caută o //legare// a variabilelor în așa fel încât operanzii să unifice. | + | * ''%%=%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D)/2|doc]]): operatorul de unificare. Dacă operanzii nu conțin variabile, atunci verifică identitatea operanzilor; altfel, caută o //legare// a variabilelor în așa fel încât operanzii să unifice. |
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%3D)/2|''%%\=%%'']]: este adevărat doar dacă cei doi operanzi nu pot unifica -- nu se poate găsi o legare a variabilelor în așa fel încât operanzii să unifice. | + | * ''%%\=%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%3D)/2|doc]]): este adevărat doar dacă cei doi operanzi nu pot unifica -- nu se poate găsi o legare a variabilelor în așa fel încât operanzii să unifice. |
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%3D)/2|''%%==%%'']] : verifică dacă doi operanzi sunt același lucru, iar eventualele variabile nelegate din operanzi sunt forțate să unifice la același lucru (printr-o unificare anterioară, de exemplu cu ''%%=%%'').<code> | + | * ''%%==%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%3D)/2|doc]]) : verifică dacă doi operanzi sunt același lucru, iar eventualele variabile nelegate din operanzi sunt forțate să unifice la același lucru (printr-o unificare anterioară, de exemplu cu ''%%=%%'').<code> |
| ?- A=B, X=A, Y=B, X==Y, writeln("Adevarat"). | ?- A=B, X=A, Y=B, X==Y, writeln("Adevarat"). | ||
| Adevarat | Adevarat | ||
| Line 279: | Line 295: | ||
| </code> | </code> | ||
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%3D%3D)/2|''%%\==%%'']]: echivalent cu ''%%\+ T1 == T2%%'' | + | * ''%%\==%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%5C%3D%3D)/2|doc]]): echivalent cu ''%%\+ T1 == T2%%'' |
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(is)/2|''%%is%%'']]: evaluează operandul din **dreapta** și | + | * ''%%is%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(is)/2|doc]]): evaluează operandul din **dreapta** și |
| * dacă în stânga este o variabilă nelegată, **leagă** această variabilă la valoarea din dreapta. | * dacă în stânga este o variabilă nelegată, **leagă** această variabilă la valoarea din dreapta. | ||
| * dacă în stânga este un număr, este echivalent cu ''%%=:=%%'' | * dacă în stânga este un număr, este echivalent cu ''%%=:=%%'' | ||
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%3A%3D)/2|''%%=:=%%'']]: operator aritmetic care returnează adevărat dacă cele două //expresii// se evaluează la același //număr//. Operanzii trebuie să fie complet instanțiați. | + | * ''%%=:=%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%3A%3D)/2|doc]]): operator aritmetic care returnează adevărat dacă cele două //expresii// se evaluează la același //număr//. Operanzii trebuie să fie complet instanțiați. |
| - | * [[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%5C%3D)/2|''%%=\=%%'']]: operator aritmetic care returnează adevărat dacă cele două //expresii// **nu** se evaluează la același //număr//. Operanzii trebuie să fie complet instanțiați. | + | * ''%%=\=%%'' ([[https://www.swi-prolog.org/pldoc/doc_for?object=(%3D%5C%3D)/2|doc]]): operator aritmetic care returnează adevărat dacă cele două //expresii// **nu** se evaluează la același //număr//. Operanzii trebuie să fie complet instanțiați. |
| Pentru o mai bună înțelegere, vom trata operatorii ''%%=%%'', ''%%is%%'', ''%%==%%'', ''%%\==%%'', ''%%=:=%%'' și ''%%=\=%%'' din mai multe perspective. | Pentru o mai bună înțelegere, vom trata operatorii ''%%=%%'', ''%%is%%'', ''%%==%%'', ''%%\==%%'', ''%%=:=%%'' și ''%%=\=%%'' din mai multe perspective. | ||
| Line 382: | Line 398: | ||
| </code> | </code> | ||
| - | ==== Tiprui de date ==== | + | ==== Tipuri de date ==== |
| Am discutat până acum de: | Am discutat până acum de: | ||
| Line 396: | Line 412: | ||
| * Lista vidă: ''%%[]%%'' | * Lista vidă: ''%%[]%%'' | ||
| - | * Lista cu elementele a, b, c: ''%%[a,b,c]%%'' | + | * Lista cu elementele a, b, c: ''%%[a, b, c]%%'' |
| - | * Lista nevidă: ''%%[Prim|Rest]%%'' – unde variabila ''%%Prim%%'' se leagă ([[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:unify|unifică]] mai bine zis) cu primul element al listei, iar variabila ''%%Rest%%'' cu lista fără acest prim element | + | * Lista nevidă: ''%%[Prim | Rest]%%'' – unde variabila ''%%Prim%%'' se leagă ([[https://www.swi-prolog.org/pldoc/man?section=glossary#gloss:unify|unifică]] mai bine zis) cu primul element al listei, iar variabila ''%%Rest%%'' cu lista fără acest prim element |
| - | * Lista care începe cu n elemente ''%%X1, X2, ..., XN%%'' și continuă cu o altă listă ''%%Rest%%'': ''%%[X1,X2,...,XN|Rest]%%'' | + | * Lista care începe cu n elemente ''%%X1, X2, ..., XN%%'' și continuă cu o altă listă ''%%Rest%%'': ''%%[X1, X2, ..., XN | Rest]%%'' |
| === Șiruri === | === Șiruri === | ||
| - | O secvență de caractere înscrisă între ''%%"%%''. | + | O secvență de caractere (un [[https://www.swi-prolog.org/pldoc/man?section=string|string]]) va fi înscrisă între ghilimele (''%%"%%''). |
| <code> | <code> | ||
| - | ?- X= "abc", string(X), writeln(X). | + | ?- X = "abc", string(X), writeln(X). |
| abc | abc | ||
| X = "abc". | X = "abc". | ||
| Line 424: | Line 440: | ||
| <HTML><li></HTML>''%%Arg2%%'' va fi neinstanțiat atunci când se va încerca satisfacerea predicatului. | <HTML><li></HTML>''%%Arg2%%'' va fi neinstanțiat atunci când se va încerca satisfacerea predicatului. | ||
| <HTML><ul></HTML> | <HTML><ul></HTML> | ||
| - | <HTML><li></HTML>Dacă predicatul este satisfăcut, ''%%Arg2%%'' va fa fi instanțiat la finalul evaluării.<HTML></li></HTML> | + | <HTML><li></HTML>Dacă predicatul este satisfăcut, ''%%Arg2%%'' va fi instanțiat la finalul evaluării.<HTML></li></HTML> |
| <HTML><li></HTML>Dacă ''%%Arg2%%'' este deja instanțiat la evaluarea predicatului, evaluarea poate servi la verificarea corectitudinii argumentului în raport cu semnificația predicatului. | <HTML><li></HTML>Dacă ''%%Arg2%%'' este deja instanțiat la evaluarea predicatului, evaluarea poate servi la verificarea corectitudinii argumentului în raport cu semnificația predicatului. | ||
| <HTML><ul></HTML> | <HTML><ul></HTML> | ||
| - | <HTML><li></HTML>Următorul exemplu, din laboratorele următore, îl folosește pe ''%%R%%'' ca o intrare, și pe ''%%N%%'' ca o ieșire.<HTML></li></HTML><HTML></ul></HTML> | + | <HTML><li></HTML>Următorul exemplu, din laboratoarele următoare, îl folosește pe ''%%R%%'' ca intrare, și pe ''%%N%%'' ca o ieșire.<HTML></li></HTML><HTML></ul></HTML> |
| <code> | <code> | ||
| Line 451: | Line 467: | ||
| * [[https://github.com/cs-pub-ro/PP-laboratoare/raw/master/prolog/intro/prolog-cheatsheet-1.pdf|Cheatsheet]] | * [[https://github.com/cs-pub-ro/PP-laboratoare/raw/master/prolog/intro/prolog-cheatsheet-1.pdf|Cheatsheet]] | ||
| * [[https://ocw.cs.pub.ro/courses/_media/pp/23/laboratoare/prolog/intro-schelet.zip|Schelet]] | * [[https://ocw.cs.pub.ro/courses/_media/pp/23/laboratoare/prolog/intro-schelet.zip|Schelet]] | ||
| - | * [[https://ocw.cs.pub.ro/courses/_media/pp/23/laboratoare/prolog/intro-solutie.zip|Soluții]] | + | * [[https://ocw.cs.pub.ro/courses/_media/pp/23/laboratoare/prolog/intro-solutii.zip|Soluții]] |
| ===== Referințe ===== | ===== Referințe ===== | ||