Sto lavorando con il libro online "Learn Prolog now" per divertimento.Devo evitare la ricorsione della coda in Prolog e in generale?
che sto cercando di scrivere un predicato che passa attraverso ciascun membro di una lista e aggiunge uno ad esso, con gli accumulatori. L'ho già fatto facilmente senza ricorsione della coda.
addone([],[]).
addone([X|Xs],[Y|Ys]) :- Y is X+1, addone(Xs,Ys).
Ma ho letto che è meglio evitare questo tipo di ricorsione per motivi di prestazioni. È vero? È considerata "buona pratica" usare sempre la ricorsione della coda? Varrà la pena di usare gli accumulatori per fare una buona abitudine?
Ho provato a modificare questo esempio in accumulatori, ma inverte l'elenco. Come posso evitare questo?
accAddOne([X|Xs],Acc,Result) :- Xnew is X+1, accAddOne(Xs,[Xnew|Acc],Result).
accAddOne([],A,A).
addone(List,Result) :- accAddOne(List,[],Result).
' addone' è già completamente ottimizzato per la coda di chiamata. È [coda ricorsiva * "modulo contro" *] (https://en.wikipedia.org/wiki/Tail_call#Tail_recursion_modulo_cons), e Prolog ha questa ottimizzazione - la nuova cella di controllo '[Y | Ys]' è allocata * prima * con i due "buchi" in essa (due logvars non ancora dimostrati, 'Y' e' Ys'), quindi 'Y' viene istanziato all'interno del corpo della regola (da' is/2'), e * quindi * la chiamata ricorsiva istanzia la variabile logica 'Ys'. Non è quindi necessario tornare dalla chiamata ricorsiva nel corpo di questa regola. –
LPN! Al giorno d'oggi ha un intero capitolo sul mostrare la differenza attraverso esempi. Per quanto ne so, Prolog è ottimizzata per la ricorsione della coda e quindi è auspicabile perché trasforma efficacemente N passi in N/2 senza arretrare. LPN: http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse20 Capitolo 5.3, gennaio 2018. –