În Prolog * toate afirmațiile și interogările se termină cu punct. * variabilele încep cu *literă mare* * afirmațiile și interogările sunt formate din *atomi* - predicate aplicate pe argumente * un predicat are un nume și argumente * un anumit predicat este identificat de numele său și de numărul de argumente * sursa specifică lucruri care *sunt adevărate* * la consolă interogările semnifică: * "este adevărat ce am întrebat?" * "pentru ce legări ale variabilelor este adevărată interogarea?" * dacă există mai multe soluții, Prolog așteaptă - "." pentru a termina interogarea - ";" pentru a căuta o nouă soluție * *Prolog încearcă să demonstreze adevărul interogărilor și să găsească legări astfel încât interogările să fie adevărate* Ce tipuri de valori există: * numere * literali/simboluri (la fel ca în Racket) -- încep doar cu literă mică * tupluri: (1,2,3) -- elementele pot fi de tipuri diferite * liste: [1,2,3] -- elementele pot fi de tipuri diferite * descompunere ca [H|T], [H1,H2|T], ... * structuri (compounds): nume(arg1, arg2, arg3) -- arată la fel ca atomii dar pot fi folosite ca argumente pentru predicate Două niveluri: * afirmațiile și interogările sunt formate doar din atomi * atomii întorc la evaluare *numai* adevărat sau fals * atomii au ca argumente valori de diverse tipuri ":-" ~~ este adevărat în condițiile în care "," ~~ și ";" ~~ sau "\+" ~~ negație Atunci când Prolog întoarce fals, înseamnă că - fie Prolog nu poate demonstra că interogarea este adevărată - fie Prolog nu poate găsi legări pentru variabile astfel încât interogarea să fie adevărată Un program Prolog definește niște relații între niște concepte. Într-o propoziție în Prolog, variabilele servesc pentru a face legături -- pentru a arăta unde ar treubi să fie aceeași valoare. -> o variabilă care apare într-un singur loc nu servește la nimic De obicei nu este nevoie să folosim =, putem să punem direct același lucru în toate locurile unde trebuie să fie același lucru. Este suficient să exprimăm lucrurile care sunt adevărate; cele care nu se pot demonstra ca adevărate sunt automat false. Egalitate = verifică faptul că operanzii *pot unifica* (pot fi legați la același lucru) și *realizează unificarea* la evaluarea lui = prolog încearcă să facă legările astfel încât operanzii să unifice = *nu* realizează evaluare aritmetică = realizează egalitatea din punct de vedere structural \= este negarea lui = ?- 1=1. true. ?- 2=1+1. false. ?- 1+1=1+1. true. ?- X=1+1. X = 1+1. ?- 1+2=2+1. false. ?- X+Y=2+1. X = 2, Y = 1. == verifică dacă operanzii unifică (fără nicio substituție suplimentară necesară). Nu realizează legări. \== este negarea lui == ?- 1+1==X+1. false. pentru că X este nelegat ?- X=Y, X+1==Y+1. X = Y. reușește pentru că am specifica anterior că X și Y trebiue să fie același lucru, și atunci cu siguranță X+1 și Y+1 vor fi același lucru =:= este egalitatea aritmetică are nevoie ca ambii operanzi să fie complet instanțiați va evalua operanzii din pdv aritmetic și va verifica egalitatea ?- 1+2=:=2+1. true. ?- X=1+1, 2 =:= X. X = 1+1. ?- 1+2=:=X. ERROR: Arguments are not sufficiently instantiated =\= este negarea lui =:= is evaluează aritmetic partea dreaptă dacă stânga este legată, evaluează egalitatea dacă stânga nu este legată, leagă la rezultatul din partea dreaptă *Atenție:* Nu putem face calcule aritmetice în argumentele predicatelor -- nu faceți p(X+1) Direcționalitatea calculului: ?- length(L, 3), member(1, L), member(2, L), member(3, L). ?- append([1,2,3], [4,5,6], L). ?- append(L1, L2, [1,2,3,4,5,6]). myReverse --------- ?- myReverse([1,2,3], [3,2,1]). primul pattern nu se potrivește a treia regulă: leagă: First1 = 1 Rest1 = [2,3] RevList1 = [3,2,1] myReverse([2,3], RevRest1) din nou a treia regulă First2 = 2 Rest2 = [3] dacă predicatul va fi adevărat, vom avea RevList2 = RevRest1 myReverse([3], RevRest2) myReverse([X], [X]) - se potrivește pentru că [3] poate unifica cu [X] RevRest2 poate unifica cu [X] ca să fie adevărat, substituim: X <- 3, RevRest2 <- [3] întoarce adevărat, se păstrează legarea RevRest2 <- [3] append(RevRest2, [First2], RevList2) este de fapt append([3], [2], RevList2) va lega RevList2 la [3, 2] acum, RevList2 = RevRest1 = [3, 2] întorc adevărat append(RevRest1, [First1], RevList1) care de fapt este append([3, 2], [1], [3,2,1]) -- verifică că este adevărat -> este întoarce adevărat este adevărat. ?- myReverse([1,2,X], [3,Y,Z]). intră în myReverse, a 3a regulă leagă First1 = 1 Rest1 = [2,X] RevList1 = [3,Y,Z] myReverse([2, X], RevRest1) pe a 3a regulă First2 = 2 Rest2 = [X] RevList2 = RevRest1 myReverse([X], RevRest2) pe a 2-a regulă [E] = [X] deci E = X RevRest2 = [E] = [X] întoarce adevărat append([X], [2], RevList2=RevRest1) întoarce adevărat, leagă: RevList2=RevRest1=[X, 2] întoarce adevărat append([X, 2], [1], [3,Y,Z]) pentru ca append să fie adevărat, trebuie ca [X,2,1]=[3,Y,Z]: X = 3 2 = Y 1 = Z întoarcem adevărat este adevărat, avem: X = 3, Y = 2, Z = 1 pentru trace: apelez predicatul trace pentru ieșire din mod trace: apelez notrace,nodebug Unificare ========= Două expresii *unifică* dacă putem găsi o legare (substituție) a variabilelor astfel încât după substituirea variabilelor, expresiile să fie același lucru. (Haskell: dacă pentru o expresie am determinat tipul Int->b și în altă parte tipul c->(d,e), atunci unificăm Int->b cu c->(d,e). Cele două expresii de tip unifică, și rezultatul este substituția { c <- Int, b <- (d,e) } ) ///> [1,X, (a,b)] unifică cu cu [Y|Z] ? Da, sub substituția { Y <- 1, Z <- [X, (a,b)] } //> *Așa cum la Haskell este important să știm ce tip ar trebui să aibă fiecare expresie, fiecare argument de funcție, fiecare variabilă, etc, la fel la Prolog trebuie să știm ce variabile mă aștept să primesc legate, și ce variabile mă aștept să le primesc ne-legate, și ce reprezintă / ce structură are fiecare variabilă.* Puterea generativă a limbajului =============================== ?- length(L, 3), member(1, L), member(2, L), member(3, L). -- folosiți ; pentru a vedea toate soluțiile ?- findall(L, (length(L, 3), member(1, L), member(2, L), member(3, L)), P). ?- X < 5. nu merge pentru că nu X nu este instanțiat //> maiMicDecat(X, 2) prima alternativă: maiMicDecat(0, 2) - adevărat-> soluție X=0 a doua alternativă: maiMicDecat(N_1, 2) rezolvă maiMicDecat(NM1_1, 2) fie maiMicDecat(0, 2) -> NM1_1=0 -> N_1=1 -> soluție X = 1 sau maiMicDecat(N_2, 2) rezolvă maiMicDecat(NM1_2, 2) fie maiMicDecat(0, 2) -> NM1_2=0, N_2=1, NM1_1=1, N_1=2 soluție X=2 sau maiMicDecat(N_3, 2) rezolv maiMicDecat(NM1_3, 2) fie maiMicDecat(0, 2) -> NM1_3=0, N_3=1 NM1_2=1, N_2=2, NM1_1=2, N_1=3 N nu este < 2 eșuează sau maiMicDecat(N_4, 2) fie maiMicDecat(0, 2) --> eșuează sau maiMicDecat(N_5, 2) fie maiMicDecat(0, 2) --> eșuează sau maiMicDeact(N_6, 2) .... *Atenție atunci când apelez predicatul recursiv cu variabile nelegate - fără a impune o limită asupra recursivității*