Curs 3Recursivitate în PROLOG. Relatii recursive. Aplicatii
Mircea [email protected]
octombrie 2014
Mircea Marin Programare logica
RecursivitateO notiune este recursiva daca este definita în functie de sine însasi.
În general, o definitie recursiva este data de una sau mai multereguli, numite si cazuri:
0 sau mai multe cazuri de baza, în care predicatul din capulregulii nu apare in corpul regulii.1 sau mai multe cazuri recursive, în care predicatul dincapul regulii apare in corpul regulii.
Multe definitii sunt recursive în PROLOG. De exemplu:
termen::= constanta | variabila| functor(termen1,...,termenn)
Cazuri de baza: Un termen este o constanta sau o variabila.Aceasta regula poate fi reformulata astfel
1 t este termen daca t este constanta.2 t este termen daca t este variabila.
Caz recursiv: t este termen daca t este de forma f (t1, . . . , tn), f esteun functor cu aritate n iar t1, . . . , tn sunt termeni.
Mircea Marin Programare logica
Recursivitate în PROLOGListe
Listele sunt o structura de date recursiva folosita frecvent încalcule simbolice. În PROLOG, listele sunt definite astfel:Cazul de baza: [ ] este o lista.Cazul inductiv: .(h, t) este lista daca h este un termen si t este
lista.
Observatii
1 Orice lista nevida l este de forma .(h, t) unde h este capul lui l(sau primul element), iar t este coada lui l .
2 Pentru liste, PROLOG permite scrierea abreviata [t1, . . . , tn] în locde .(t1, .(..., .(tn, [])...)). Termenii t1, . . . , tn se numesc elementelelistei, si pot fi orice fel de termeni: constante, variabile saustructuri. De exemplu:[lista, cu,4,elemente,′ :′, [a, A, carte(ion,autor(rebreanu)), _]]
3 În PROLOG, un sir "a1, . . . ,an" este de fapt lista codurilor ASCIIale caracterelor a1, . . . ,an.
Mircea Marin Programare logica
Manipularea listelorCap si coada (engl. head and tail)
Notatie speciala pentru despartirea unei liste L în cap si coada:[X | Y ] = L
B variabila X va fi legata la capul listei LB variabla Y va fi legata la coada listei L.
OBSERVATIE.[X |Y ] este de fapt termenul .(X ,Y ).[X | Y ] nu este o lista!
Exemplu
Lista Cap Coada[a,b, c,d ] a [b, c,d ][a] a [][] (nimic) (nimic)[[cainele, rau],musca] [cainele rau] [musca][X + Y , x + y ] [X + Y ] [x + y ]"abc" 97 [98,99]
Mircea Marin Programare logica
Manipularea listelorCap si coada (engl. head and tail)
Notatie speciala pentru despartirea unei liste L în cap si coada:[X | Y ] = L
B variabila X va fi legata la capul listei LB variabla Y va fi legata la coada listei L.
OBSERVATIE.[X |Y ] este de fapt termenul .(X ,Y ).[X | Y ] nu este o lista!
Exemplu
Lista Cap Coada[a,b, c,d ] a [b, c,d ][a] a [][] (nimic) (nimic)[[cainele, rau],musca] [cainele rau] [musca][X + Y , x + y ] [X + Y ] [x + y ]"abc" 97 [98,99]
Mircea Marin Programare logica
Definitii recursive de predicate
Exemplu 1: Definitia unui predicat de recunoastere a listelor% este_lista(L) inseamna ca L este lista
% Caz de bazaeste_lista([]).
% Caz recursiveste_lista([_|T]) :- este_lista(T).
Exemplu 2: Definitia relatiei de apartenenta la o lista% membru(X,L) inseamna ca X apare in lista L
% Caz de baza: X este capul listei Lmembru(X,[X|_]).
% Caz recursiv: X apare in coada listei Lmembru(X,[Y|T]) :- membru(X,T).
Mircea Marin Programare logica
Definitii recursive de predicate
Exemplu 1: Definitia unui predicat de recunoastere a listelor% este_lista(L) inseamna ca L este lista
% Caz de bazaeste_lista([]).
% Caz recursiveste_lista([_|T]) :- este_lista(T).
Exemplu 2: Definitia relatiei de apartenenta la o lista% membru(X,L) inseamna ca X apare in lista L
% Caz de baza: X este capul listei Lmembru(X,[X|_]).
% Caz recursiv: X apare in coada listei Lmembru(X,[Y|T]) :- membru(X,T).
Mircea Marin Programare logica
Teste de apartenenta
?- membru(a,[a,b,c]).true .
?- membru(b,[a,b,c]).true .
?- membru(d,[a,b,c]).false.
Mircea Marin Programare logica
Teste de apartenenta
OBSERVATII
PROLOG verifica 2 conditii, în ordinea urmatoare:1 membru(X,[X|_]). (caz de baza)2 membru(X,[_|T]) :- membru(X,T). (caz recursiv)
În cazul recursiv, lista testata pentru aparitia lui X în eadevine tot mai mica.Lista nu se poate micsora la nesfârsit ⇒ calculul setermina.PROLOG se opreste din testat în 2 situatii:
1 S-a dat de o lista care satisface cazul de baza⇒ testul se termina cu succes (true).
2 S-a ajuns la lista vida⇒ testul se termina cu esec (false).
Mircea Marin Programare logica
Teste de apartenenta
Ce se întâmpla daca PROLOG este pus sa raspunda laîntrebarile urmatoare??- membru(X,[a,b,c]).?- membru(a,X).?- membru(X,Y).?- membru(X,_).?- membru(_,Y).?- membru(_,_).
Mircea Marin Programare logica
Teste de apartenenta
membru(X,[X|Y]). %1membru(X,[Y|T]):-membru(X,T). %2?-membru(a,X).
membru(a,X).
� membru(a,T2).
� membru(a,T3).
membru(X1,[X1|Y1]).X1=a, X=[a|Y1].
membru(X2,[Y2|T2]):-membru(X2,T2).X2=a, X=[Y2|T2].
membru(X3,[X3|Y3]).X3=a, T2=[a|Y3].
membru(X3,[Y3|T3]):-membru(X3,T3).X3=a, T2=[Y3|T3].
Mircea Marin Programare logica
RecursieProbleme de terminare
Terminare = proprietate a unui program de a se terminadupa un numar finit de pasi.Unele programe nu se termina
parinte(X,Y) :- fiu(Y,X).fiu(Y,X) :- parinte(X,Y).
Motivul: definitiile lui parinte/2 si fiu/2 sunt circulare.⇒ evitati definitiile circulare!
Programul urmator este recursiv la stânga si nu se termina:
om(X):-om(Y), parinte(X,Y).om(adam).
⇒ recursia la stânga trebuie folosita cu grija!
Mircea Marin Programare logica
RecursieProbleme de terminare
Regulile si faptele se aplica în ordinea în care apar în program
criteriu intuitiv: faptele trebuiesc puse înaintea regulilor.
Uneori, regulile ordonate într-un anumit fel functioneaza bine pentruun anumit tip de întrebari.
Exemplu
este_lista([_|B]):-este_lista(B).este_lista([]).
este un program adecvat pentru întrebarile
?-este_lista([1,2,3]).?-este_lista([]).?-este_lista(f(1,2))
dar nu este adecvat pentru este_lista(X).Ce se întâmpla daca se schimba ordinea clauzelor din program??-este_lista(X).
Mircea Marin Programare logica
RecursivitateDirectia de construire a solutiilor
Numeroase predicate definite în Prolog fac distinctie întreParametri de intrare (-): trebuie sa aiba valori concrete atunci
când se apeleaza predicatul.Parametri de iesire (+): valorile lor sunt calculate ca raspuns.Parametri arbitrari (?): pot fi fie de intrare sau iesire.
Mircea Marin Programare logica
RecursivitateExemplu
% nr_elem(+Lista,-N) calculeaza numarul de elemente N al listei% Lista. Lista este param. de intrare, iar N este param. de iesire.nr_elem([],0). %1nr_elem([_|T],N):-nr_elem(T,N1), N is N1+1. %2
nr_elem([a,b],N).
nr_elem([b],N1), N is N1+1.
nr_elem([],N2), N1 is N2+1.
�
(2)
(2)
(1)N2=0
N1=1
N=2
Observatii:
Solutia pentru numarul de elemente N din lista este construita pe ramura derevenire din recursivitate:
Este de dorit calculul rezultatului pe ramura de avans în recursivitate, pentru aevita crearea de variabile temporare pe stiva.
Mircea Marin Programare logica
RecursivitateExemplu
% nr_elem(+Lista,-N) calculeaza numarul de elemente N al listei% Lista. Lista este param. de intrare, iar N este param. de iesire.nr_elem([],0). %1nr_elem([_|T],N):-nr_elem(T,N1), N is N1+1. %2
nr_elem([a,b],N).
nr_elem([b],N1), N is N1+1.
nr_elem([],N2), N1 is N2+1.
�
(2)
(2)
(1)N2=0
N1=1
N=2
Observatii:
Solutia pentru numarul de elemente N din lista este construita pe ramura derevenire din recursivitate:
Este de dorit calculul rezultatului pe ramura de avans în recursivitate, pentru aevita crearea de variabile temporare pe stiva.
Mircea Marin Programare logica
RecursivitateExemplu
% nr_elem(+Lista,-N) calculeaza numarul de elemente N al listei% Lista. Lista este param. de intrare, iar N este param. de iesire.nr_elem([],0). %1nr_elem([_|T],N):-nr_elem(T,N1), N is N1+1. %2
nr_elem([a,b],N).
nr_elem([b],N1), N is N1+1.
nr_elem([],N2), N1 is N2+1.
�
(2)
(2)
(1)N2=0
N1=1
N=2
Observatii:
Solutia pentru numarul de elemente N din lista este construita pe ramura derevenire din recursivitate:
Este de dorit calculul rezultatului pe ramura de avans în recursivitate, pentru aevita crearea de variabile temporare pe stiva.
Mircea Marin Programare logica
RecursivitateExemplu
% nr_elem(+Lista,-N) calculeaza numarul de elemente N al listei% Lista. Lista este param. de intrare, iar N este param. de iesire.nr_elem([],0). %1nr_elem([_|T],N):-nr_elem(T,N1), N is N1+1. %2
nr_elem([a,b],N).
nr_elem([b],N1), N is N1+1.
nr_elem([],N2), N1 is N2+1.
�
(2)
(2)
(1)N2=0
N1=1
N=2
Observatii:
Solutia pentru numarul de elemente N din lista este construita pe ramura derevenire din recursivitate:
Este de dorit calculul rezultatului pe ramura de avans în recursivitate, pentru aevita crearea de variabile temporare pe stiva.
Mircea Marin Programare logica
RecursivitateCalculul numarului de elemente al unei liste: Versiunea cu acumulator
Varianta nr_elem1(Lista,N) de calcul al numarului de elemente din L pe ramurade avans în recursivitate se bazeaza pe relatia ajutatoare nr_elemAux(Lista,A,N)unde:
A este un argument suplimentar fata de nr_elem(Lista,N), numit acumulator.A acumuleaza numarul de elemente din lista pe masura ce se avanseaza înrecursivitate.
nr_elem1(Lista,N):-nr_elemAux(Lista,0,N). %1nr_elemAux([],N,N). %2nr_elemAux([_|T],M,N):-P is M+1,nr_elemAux(T,P,N). %3
nr_elem1([a,b],N).
nr_elemAux([a,b],0,N).
(1) nr_elem1(Lista0,N0):-nr_elemAux(Lista0,0,N0).Lista0=[a,b], N0=N.
nr_elemAux([a],1,N).
(3) nr_elemAux([_|T1],M1,N1):-P1 is M1+1,nr_elemAux(T1,P1,N1).T1=[b], M1=0,P1=1.
nr_elemAux([],2,N).
(3) nr_elemAux([_|T2],M2,N2):-P2 is M2+1,nr_elemAux(T2,P2,N2).T2=[], M2=1,P2=2.
�
(2) nr_elemAux([],N3,N3).N3=2, N=2
Mircea Marin Programare logica
RecursivitateCalculul numarului de elemente al unei liste: Versiunea cu acumulator
Varianta nr_elem1(Lista,N) de calcul al numarului de elemente din L pe ramurade avans în recursivitate se bazeaza pe relatia ajutatoare nr_elemAux(Lista,A,N)unde:
A este un argument suplimentar fata de nr_elem(Lista,N), numit acumulator.A acumuleaza numarul de elemente din lista pe masura ce se avanseaza înrecursivitate.
nr_elem1(Lista,N):-nr_elemAux(Lista,0,N). %1nr_elemAux([],N,N). %2nr_elemAux([_|T],M,N):-P is M+1,nr_elemAux(T,P,N). %3
nr_elem1([a,b],N).
nr_elemAux([a,b],0,N).
(1) nr_elem1(Lista0,N0):-nr_elemAux(Lista0,0,N0).Lista0=[a,b], N0=N.
nr_elemAux([a],1,N).
(3) nr_elemAux([_|T1],M1,N1):-P1 is M1+1,nr_elemAux(T1,P1,N1).T1=[b], M1=0,P1=1.
nr_elemAux([],2,N).
(3) nr_elemAux([_|T2],M2,N2):-P2 is M2+1,nr_elemAux(T2,P2,N2).T2=[], M2=1,P2=2.
�
(2) nr_elemAux([],N3,N3).N3=2, N=2
Mircea Marin Programare logica
RecursivitateCalculul numarului de elemente al unei liste: Versiunea cu acumulator
Varianta nr_elem1(Lista,N) de calcul al numarului de elemente din L pe ramurade avans în recursivitate se bazeaza pe relatia ajutatoare nr_elemAux(Lista,A,N)unde:
A este un argument suplimentar fata de nr_elem(Lista,N), numit acumulator.A acumuleaza numarul de elemente din lista pe masura ce se avanseaza înrecursivitate.
nr_elem1(Lista,N):-nr_elemAux(Lista,0,N). %1nr_elemAux([],N,N). %2nr_elemAux([_|T],M,N):-P is M+1,nr_elemAux(T,P,N). %3
nr_elem1([a,b],N).
nr_elemAux([a,b],0,N).
(1) nr_elem1(Lista0,N0):-nr_elemAux(Lista0,0,N0).Lista0=[a,b], N0=N.
nr_elemAux([a],1,N).
(3) nr_elemAux([_|T1],M1,N1):-P1 is M1+1,nr_elemAux(T1,P1,N1).T1=[b], M1=0,P1=1.
nr_elemAux([],2,N).
(3) nr_elemAux([_|T2],M2,N2):-P2 is M2+1,nr_elemAux(T2,P2,N2).T2=[], M2=1,P2=2.
�
(2) nr_elemAux([],N3,N3).N3=2, N=2
Mircea Marin Programare logica
RecursivitateCalculul numarului de elemente al unei liste: Versiunea cu acumulator
Varianta nr_elem1(Lista,N) de calcul al numarului de elemente din L pe ramurade avans în recursivitate se bazeaza pe relatia ajutatoare nr_elemAux(Lista,A,N)unde:
A este un argument suplimentar fata de nr_elem(Lista,N), numit acumulator.A acumuleaza numarul de elemente din lista pe masura ce se avanseaza înrecursivitate.
nr_elem1(Lista,N):-nr_elemAux(Lista,0,N). %1nr_elemAux([],N,N). %2nr_elemAux([_|T],M,N):-P is M+1,nr_elemAux(T,P,N). %3
nr_elem1([a,b],N).
nr_elemAux([a,b],0,N).
(1) nr_elem1(Lista0,N0):-nr_elemAux(Lista0,0,N0).Lista0=[a,b], N0=N.
nr_elemAux([a],1,N).
(3) nr_elemAux([_|T1],M1,N1):-P1 is M1+1,nr_elemAux(T1,P1,N1).T1=[b], M1=0,P1=1.
nr_elemAux([],2,N).
(3) nr_elemAux([_|T2],M2,N2):-P2 is M2+1,nr_elemAux(T2,P2,N2).T2=[], M2=1,P2=2.
�
(2) nr_elemAux([],N3,N3).N3=2, N=2
Mircea Marin Programare logica
RecursivitateCalculul numarului de elemente al unei liste: Versiunea cu acumulator
Varianta nr_elem1(Lista,N) de calcul al numarului de elemente din L pe ramurade avans în recursivitate se bazeaza pe relatia ajutatoare nr_elemAux(Lista,A,N)unde:
A este un argument suplimentar fata de nr_elem(Lista,N), numit acumulator.A acumuleaza numarul de elemente din lista pe masura ce se avanseaza înrecursivitate.
nr_elem1(Lista,N):-nr_elemAux(Lista,0,N). %1nr_elemAux([],N,N). %2nr_elemAux([_|T],M,N):-P is M+1,nr_elemAux(T,P,N). %3
nr_elem1([a,b],N).
nr_elemAux([a,b],0,N).
(1) nr_elem1(Lista0,N0):-nr_elemAux(Lista0,0,N0).Lista0=[a,b], N0=N.
nr_elemAux([a],1,N).
(3) nr_elemAux([_|T1],M1,N1):-P1 is M1+1,nr_elemAux(T1,P1,N1).T1=[b], M1=0,P1=1.
nr_elemAux([],2,N).
(3) nr_elemAux([_|T2],M2,N2):-P2 is M2+1,nr_elemAux(T2,P2,N2).T2=[], M2=1,P2=2.
�
(2) nr_elemAux([],N3,N3).N3=2, N=2
Mircea Marin Programare logica
AcumulatoriAplicatie: Inversarea unei liste
Sa se defineasca relatia rev_lista(L,R) care are loc dacaR este inversa listei L.
Idee: Se foloseste un acumulator care actioneaza ca ostiva în care se pun recursiv toate elementele lui L,începând cu capul lui L.Initial, acumulatorul este [].rev_lista(L,R):-rev_listaAux(L,[],R).
% caz de bazarev_listaAux([],R,R).
%caz recursivrev_listaAux([H|T],A,R):-rev_listaAux(T,[H|A],R).
Mircea Marin Programare logica
AcumulatoriAplicatie: Inversarea unei liste
Sa se defineasca relatia rev_lista(L,R) care are loc dacaR este inversa listei L.
Idee: Se foloseste un acumulator care actioneaza ca ostiva în care se pun recursiv toate elementele lui L,începând cu capul lui L.
Initial, acumulatorul este [].rev_lista(L,R):-rev_listaAux(L,[],R).
% caz de bazarev_listaAux([],R,R).
%caz recursivrev_listaAux([H|T],A,R):-rev_listaAux(T,[H|A],R).
Mircea Marin Programare logica
AcumulatoriAplicatie: Inversarea unei liste
Sa se defineasca relatia rev_lista(L,R) care are loc dacaR este inversa listei L.
Idee: Se foloseste un acumulator care actioneaza ca ostiva în care se pun recursiv toate elementele lui L,începând cu capul lui L.Initial, acumulatorul este [].
rev_lista(L,R):-rev_listaAux(L,[],R).
% caz de bazarev_listaAux([],R,R).
%caz recursivrev_listaAux([H|T],A,R):-rev_listaAux(T,[H|A],R).
Mircea Marin Programare logica
AcumulatoriAplicatie: Inversarea unei liste
Sa se defineasca relatia rev_lista(L,R) care are loc dacaR este inversa listei L.
Idee: Se foloseste un acumulator care actioneaza ca ostiva în care se pun recursiv toate elementele lui L,începând cu capul lui L.Initial, acumulatorul este [].rev_lista(L,R):-rev_listaAux(L,[],R).
% caz de bazarev_listaAux([],R,R).
%caz recursivrev_listaAux([H|T],A,R):-rev_listaAux(T,[H|A],R).
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).
R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
Inversarea unei liste: varianta cu acumulator
Exemplu ilustrat?-rev_lista([a,b,c],R).R=[c,b,a]
rev_lista([a,b,c],R).
rev_listaAux([a,b,c],[],R).
rev_lista(L1,R1):-rev_listaAux(L1,[],R1).L1=[a,b,c], R1=R
rev_listaAux([b,c],[a],R).
rev_listaAux([H2|T2],A2,R2):-rev_listaAux(T2,[H2|A2],R2).
H2=[a],T2=[b,c], A2=[],R2=R
rev_listaAux([c],[b,a],R).
rev_listaAux([H3|T3],A3,R3):-rev_listaAux(T3,[H3|A3],R3).
H3=[b],T3=[c], A3=[a],R3=R
rev_listaAux([],[c,b,a],R).
rev_listaAux([H4|T4],A4,R4):-rev_listaAux(T4,[H4|A4],R4).
H4=[c],T4=[], A4=[b,a],R4=R
�
rev_listaAux([],R5,R5).R5=[c,b,a], R=[c,b,a]
Mircea Marin Programare logica
RecursivitateAplicatie: Problema trezorierului
Ipoteze:1 Nici un membru al clubului nu are datorii la trezorierul clubului.2 Daca un membru al clubului nu a platit taxa, atunci el are datorii la trezorierul
clubului.3 Trezorierul clubului este un membru al clubului.
Concluzie: Trezorierul clubului a platit taxa.
Sa se rescrie problema ca fapte, reguli si întrebare în Prolog.
%Ipoteza 1fara_datorii(X):-membru_club(X).%Ipotexa 2platit_taxa(X):-fara_datorii(X).%Ipoteza 3membru_club(trezorier).
?-platit_taxa(trezorier).
Observatie: un astfel de program nu este recursiv.
Mircea Marin Programare logica
RecursivitateAplicatie: Problema trezorierului
Ipoteze:1 Nici un membru al clubului nu are datorii la trezorierul clubului.2 Daca un membru al clubului nu a platit taxa, atunci el are datorii la trezorierul
clubului.3 Trezorierul clubului este un membru al clubului.
Concluzie: Trezorierul clubului a platit taxa.
Sa se rescrie problema ca fapte, reguli si întrebare în Prolog.
%Ipoteza 1fara_datorii(X):-membru_club(X).%Ipotexa 2platit_taxa(X):-fara_datorii(X).%Ipoteza 3membru_club(trezorier).
?-platit_taxa(trezorier).
Observatie: un astfel de program nu este recursiv.
Mircea Marin Programare logica
RecursivitateAplicatie: Problema vecinilor
Sa se formalizeze urmatoarele cunostinte în Prolog:1 Stefan este vecin cu Petre.2 Stefan este casatorit cu o doctorita care lucreaza la Spitalul de Urgenta.3 Petre este casatorit cu o actrita care lucreaza la Teatrul National.4 Stefan este meloman si Petre este vânator.5 Toti melomanii sunt sentimentali.6 Toti vânatorii sunt mincinosi.7 Actritelor le plac barbatii sentimentali.8 Sotii au aceiasi vecini.9 Casatoria si vecinatatea sunt relatii simetrice.
Apoi sa se foloseasca Prolog pentru a afla raspunsul la întrebarea: Îi place sotiei lui
Petre de Stefan?
Mircea Marin Programare logica
RecursivitateAplicatie: Problema vecinilor.
vecin1(stefan,petre). %1casatorit1(stefan,sotie_stefan). %2doctorita(sotie_stefan). %2lucreaza(sotie_stefan,urgenta). %2casatorit1(petre,sotie_petre). %3actrita(sotie_petre). %3lucreaza(sotie_petre,national). %3meloman(stefan). %4vanator(petre). %4sentimental(X):-meloman(X). %5mincinos(X):-vanator(X). %6place(X,Y):-actrita(X),sentimental(Y). %7vecin(X,Y):-casatorit(X,Z),vecin(Z,Y). %8vecin(X,Y):-vecin1(X,Y). %9vecin(X,Y):-vecin1(Y,X). %9casatorit(X,Y):-casatorit1(X,Y). %9casatorit(X,Y):-casatorit1(Y,X). %9concluzie:-casatorit(petre,Sotie),place(Sotie,stefan).
?-concluzie.
Observatie: Acest program este recursiv.
Mircea Marin Programare logica
Observatii referitoare la relatii simetrice
O relatie binara r este simetrica daca
r(term1,term2) are loc daca si numai daca r(term2,term1) are loc.
Relatiile vecin/2 si casatorit/2 din exemplul precedent sunt simetrice.
Q: Cum se poate specifica o relatie simetrica?
Varianta 1 - Exemplur(a,b). r(a,c).r(X,Y):-r(Y,X).
Observatie: Este esential ca faptele pentru r/2 sa apara înaintea regulii.Problema:
?-r(b,c).
⇒ raspunsul la aceasta întrebare nu va fi obtinut niciodata (calcul infinit).Cum putem evita aceste calcule infinite?
Varianta 2: prin intermediul unei relatiei binare asimetrice r1/2. Exemplu:r1(a,b). r1(a,c).r(X,Y):-r1(X,Y).r(X,Y):-r1(Y,X).
Aceasta varianta a fost folosita pentru a defini relatiile simetrice vecin/2 sicasatorit/2.
Mircea Marin Programare logica
Observatii referitoare la relatii simetrice
O relatie binara r este simetrica daca
r(term1,term2) are loc daca si numai daca r(term2,term1) are loc.
Relatiile vecin/2 si casatorit/2 din exemplul precedent sunt simetrice.
Q: Cum se poate specifica o relatie simetrica?
Varianta 1 - Exemplur(a,b). r(a,c).r(X,Y):-r(Y,X).
Observatie: Este esential ca faptele pentru r/2 sa apara înaintea regulii.Problema:
?-r(b,c).
⇒ raspunsul la aceasta întrebare nu va fi obtinut niciodata (calcul infinit).Cum putem evita aceste calcule infinite?
Varianta 2: prin intermediul unei relatiei binare asimetrice r1/2. Exemplu:r1(a,b). r1(a,c).r(X,Y):-r1(X,Y).r(X,Y):-r1(Y,X).
Aceasta varianta a fost folosita pentru a defini relatiile simetrice vecin/2 sicasatorit/2.
Mircea Marin Programare logica
Observatii referitoare la relatii simetrice
O relatie binara r este simetrica daca
r(term1,term2) are loc daca si numai daca r(term2,term1) are loc.
Relatiile vecin/2 si casatorit/2 din exemplul precedent sunt simetrice.
Q: Cum se poate specifica o relatie simetrica?
Varianta 1 - Exemplur(a,b). r(a,c).r(X,Y):-r(Y,X).
Observatie: Este esential ca faptele pentru r/2 sa apara înaintea regulii.Problema:
?-r(b,c).
⇒ raspunsul la aceasta întrebare nu va fi obtinut niciodata (calcul infinit).Cum putem evita aceste calcule infinite?
Varianta 2: prin intermediul unei relatiei binare asimetrice r1/2. Exemplu:r1(a,b). r1(a,c).r(X,Y):-r1(X,Y).r(X,Y):-r1(Y,X).
Aceasta varianta a fost folosita pentru a defini relatiile simetrice vecin/2 sicasatorit/2.
Mircea Marin Programare logica
Observatii referitoare la relatii simetrice
O relatie binara r este simetrica daca
r(term1,term2) are loc daca si numai daca r(term2,term1) are loc.
Relatiile vecin/2 si casatorit/2 din exemplul precedent sunt simetrice.
Q: Cum se poate specifica o relatie simetrica?
Varianta 1 - Exemplur(a,b). r(a,c).r(X,Y):-r(Y,X).
Observatie: Este esential ca faptele pentru r/2 sa apara înaintea regulii.Problema:
?-r(b,c).
⇒ raspunsul la aceasta întrebare nu va fi obtinut niciodata (calcul infinit).Cum putem evita aceste calcule infinite?
Varianta 2: prin intermediul unei relatiei binare asimetrice r1/2. Exemplu:r1(a,b). r1(a,c).r(X,Y):-r1(X,Y).r(X,Y):-r1(Y,X).
Aceasta varianta a fost folosita pentru a defini relatiile simetrice vecin/2 sicasatorit/2.
Mircea Marin Programare logica
Reprezentarea multimilor în Prolog
O multime poate fi reprezentata ca o lista în care fiecare elementapare o singura data.
Sa se defineasca recursiv proprietatea este_multime(L) careare loc daca L este o lista în care fiecare element apare osingura data. Exemplu:
?-este_multime([a,b,d,c]).true?-este_multime([a,b,a]).false
Sa se defineasca relatia multime(L,M) care ia ca argumentde intrare o lista L si foloseste M ca parametru de iesire pentrumultimea de elemente care apar în lista L.
?-multime([a,b,a,c],M).M=[a,b,c]
Mircea Marin Programare logica
Reprezentarea multimilor în Prolog
1 este_multime(L)B Cazul de baza: [] este multime.B Cazul recursiv: [H|T] este multime daca H nu apare în T si
T este multime.2 multime(L,M)
B Cazul de baza: Daca L=[] atunci M=[].B Cazul recursiv: Daca L=[H|T] atunci M=[H|R] unde R
este lista obtinuta în 2 pasi:1 Mai întâi se determina lista R1 care se obtine stergând din T
toate aparitiile lui H.Pentru a afla R1, vom defini relatia sterge(H,T,R1) careare loc daca R1 este lista care se obtine din T stergând toateaparitiile lui H.
2 R se obtine recursiv, ca raspuns la întrebareamultime(R1,R).
Mircea Marin Programare logica
Reprezentarea multimilor în Prolog
este_multime([]).este_multime([H|T]):-not(member(H,T)),
este_multime(T).
B not este operator predefinit în Prolog. ?-not(atom) are locdaca si numai daca ?-atom nu are loc.
B member(X,L) este predefinit în Prolog, si are loc daca si numaidaca X este membru al listei L.
multime([],[]).multime([H|T],[H|R]):-sterge(H,T,R1),multime(R1,R).
sterge(H,[],[]).sterge(H,[H|T],R):-sterge(H,T,R).sterge(H,[H1|T],[H1|R]):-H\=H1,
sterge(H,T,R).
Mircea Marin Programare logica
Reprezentarea multimilor în Prolog
este_multime([]).este_multime([H|T]):-not(member(H,T)),
este_multime(T).
B not este operator predefinit în Prolog. ?-not(atom) are locdaca si numai daca ?-atom nu are loc.
B member(X,L) este predefinit în Prolog, si are loc daca si numaidaca X este membru al listei L.
multime([],[]).multime([H|T],[H|R]):-sterge(H,T,R1),multime(R1,R).
sterge(H,[],[]).sterge(H,[H|T],R):-sterge(H,T,R).sterge(H,[H1|T],[H1|R]):-H\=H1,
sterge(H,T,R).
Mircea Marin Programare logica
Operatii cu multimiExercitii
Sa se defineasca recursiv urmatoarele relatii pentru multimi:multimi_egale(A,B) daca A si B sunt multimi egale.reuniune(A,B,C) care are loc daca C reprezintamultimea obtinuta din reuniunea multimilor A si B.intersectie(A,B,C) care are loc daca C reprezintamultimea obtinuta din intersectia multimilor A si B.diferenta(A,B,C) care are loc daca C reprezintamultimea obtinuta prin scaderea multimilor A si B.
Mircea Marin Programare logica
Relatii recursiveQuiz
Se considera relatia next(X,Y,L) definita astfel:
next(X,Y,[X,Y|_]).next(X,Y,[Z|T]):-X\=Z,next(X,Y,T).
1 Care este semnificatia relatiei next(X,Y,Z)?
2 Care este semnificatia predicatului z_u(X,Y) definit de regula
z_u(X,Y):-next(X,Y,[luni,marti,miercuri,joi,vineri,sambata,duminica,luni]).
3 Care este semnificatia predicatului z_u(X,Y) definit de regula
z_p(X,Y):-z_u(Y,X).
Mircea Marin Programare logica