Patru ipostaze al recursivitatii in contextul prelucrarii secventiale a listelor in Prolog

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Patru ipostaze al recursivitatii in contextul prelucrarii secventiale a listelor in Prolog % Nicolaie Popescu-Bodorin, 2009 % http://fmi.spiruharet.ro/bodorin/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Ca exemplu vom considera urmatoarea prelucrare: pentru o lista data, toate elementele egale cu un numar dat N % se substituie cu 2N. DOMAINS r=real lr=r* PREDICATES cm1(r,lr,lr) cm1(r,lr,lr,lr) cm2(r,lr,lr) cm3(r,lr,lr) cm4(r,lr,lr) CLAUSES % 1. Forward tail-recursion with accumulator(s): % Una din posibilitatile de a efectua o prelucrare secventiala a unei liste in Prolog este folosirea unei variabile % acumulator: cm1(X,L,R):-cm(X,L,[],R). % Instructiunea de schimbare de aritate introduce variabila acumulator % pe pozitia a treia in lista parametrilor de apel. cm1(_,[],Ri,Ri). % Fapt de oprire (cel mai interior aoutoapel): daca lista s-a epuizat, % rezultatul intermediac acumulat pana in cel mai interior autoapel este % (unificat) chiar (cu) rezultatul final. cm1(X,[H|T],Ri,R):- X=H,Y=2*X, Ria=[Y|Ri],cm1(X,T,Ria,R); X<>H, Ria=[H|Ri],cm1(X,T,Ria,R). % Clauza de propagare a autoapelului specifica modul in care variabila % acumulator colecteaza date odata cu parcurgerea listei, in functie de % aparitia numarului cautat sau a unui numar diferit. % 2. Backward regular recursion: cm2(_,[],[]). % Fapt de oprire. cm2(X,[H|T],R):- % Abordarea recursiva "inapoi" consta in descrierea legaturii care exista % intre rezultatul calculului pe lista data si rezultatul calculului pe sublista % obtinuta prin eliminarea capului listei date. X=H,Y=2*X, cm2(X,T,Ri),R=[Y|Ri]; % Si aici, clauza de propagare a autoapelului specifica modul in care % variabila acumulator colecteaza date odata cu parcurgerea listei, in % functie de aparitia numarului cautat sau a unui numar diferit. X<>H, cm2(X,T,Ri), R=[H|Ri]. % O abordare de acest tip este usor de recunoscut datorita prezentei % dupa autoapeluri a relatiei de legatura dintre rezultate (aici R si Ri). % 3. Trecerea de la "backward regular recursion" la "backward tail recursion" in cazul listelor prelucrate secventia: cm3(_,[],[]). % Fapt de oprire. cm3(X,[H|T],[Y|Rt]) :- % Se remarca faptul ca, in aceasta clauza de propagare, ultima instructiune % este, pe toate alternativele, autoapelul. Predicatul astfel definit este % deci recursiv la urma (tail recursive). X=H,Y=2*X, cm3(X,T,Rt); % Si aici, clauza de propagare a autoapelului specifica modul in care % variabila acumulator colecteaza date odata cu parcurgerea listei, % in functie de aparitia numarului cautat sau a unui numar diferit. X<>H,Y=H, cm3(X,T,Rt). % In cazul particular al prelucrarilor secventiale, relatia de legatura dintre % rezultate "migreaza" in lista de apel a predicatului (aici sub forma [Y|Rt]). % Este deci de retinunt ca, in cazul prelucrarilor secventiale pe liste, trecerea de la "backward regular recursion" la % "backward tail recursion" este, de regula, posibila fara schimbarea aritatii predicatului. % 4. A patra varianta de calcul a aceluiasi predicat este tot una de tip "backward tail recursion" care, in plus, % minimizeaza numarul de operatii necesare: cm4(_,[],[]). cm4(X,[X|T],[H|Rt]) :- H=2*X, cm4(X,T,Rt),!. cm4(X,[H|T],[H|Rt]):-cm4(X,T,Rt).